Using JZMQ with EPGM Transport Is Not Sending or Receiving Data

836 Views Asked by At

I'm experimenting with java flavored zmq to test the benefits of using PGM over TCP in my project. So I changed the weather example, from the zmq guide, to use the epgm transport. Everything compiles and runs, but nothing is being sent or received. If I change the transport back to TCP, the server receives the messages sent from the client and I get the console output I'm expecting.

So, what are the requirements for using PGM? I changed the string, that I'm passing to the bind and connect methods, to follow the zmq api for zmq_pgm: "transport://interface;multicast address:port". That didn't work. I get and invalid argument error whenever I attempt to use this format. So, I simplified it by dropping the interface and semicolon which "works", but I'm not getting any results.

I haven't been able to find a jzmq example that uses pgm/epgm and the api documentation for the java binding does not define the appropriate string format for an endpoint passed to bind or connect. So what am I missing here? Do I have to use different hosts for the client and the server?

One thing of note is that I'm running my code on a VirtualBox VM (Ubuntu 14.04/OSX Mavericks host). I'm not sure if that has anything to do with the issue I'm currently facing.

Server:

public class wuserver {

public static void main (String[] args) throws Exception {
    //  Prepare our context and publisher
    ZMQ.Context context = ZMQ.context(1);

    ZMQ.Socket publisher = context.socket(ZMQ.PUB);
    publisher.bind("epgm://xx.x.x.xx:5556");
    publisher.bind("ipc://weather");

    //  Initialize random number generator
    Random srandom = new Random(System.currentTimeMillis());
    while (!Thread.currentThread ().isInterrupted ()) {
        //  Get values that will fool the boss
        int zipcode, temperature, relhumidity;
        zipcode = 10000 + srandom.nextInt(10000) ;
        temperature = srandom.nextInt(215) - 80 + 1;
        relhumidity = srandom.nextInt(50) + 10 + 1;

        //  Send message to all subscribers
        String update = String.format("%05d %d %d", zipcode, temperature, relhumidity);
        publisher.send(update, 0);
    }

    publisher.close ();
    context.term ();
   }
}

Client:

public class wuclient {

public static void main (String[] args) {
    ZMQ.Context context = ZMQ.context(1);

    //  Socket to talk to server
    System.out.println("Collecting updates from weather server");
    ZMQ.Socket subscriber = context.socket(ZMQ.SUB);
    //subscriber.connect("tcp://localhost:5556");
    subscriber.connect("epgm://xx.x.x.xx:5556");

    //  Subscribe to zipcode, default is NYC, 10001
    String filter = (args.length > 0) ? args[0] : "10001 ";
    subscriber.subscribe(filter.getBytes());

    //  Process 100 updates
    int update_nbr;
    long total_temp = 0;
    for (update_nbr = 0; update_nbr < 100; update_nbr++) {
        //  Use trim to remove the tailing '0' character
        String string = subscriber.recvStr(0).trim();

        StringTokenizer sscanf = new StringTokenizer(string, " ");
        int zipcode = Integer.valueOf(sscanf.nextToken());
        int temperature = Integer.valueOf(sscanf.nextToken());
        int relhumidity = Integer.valueOf(sscanf.nextToken());

        total_temp += temperature;

    }
    System.out.println("Average temperature for zipcode '"
            + filter + "' was " + (int) (total_temp / update_nbr));

    subscriber.close();
    context.term();
  }
}
2

There are 2 best solutions below

3
On

There are a couple possibilities:

  • You need to make sure ZMQ is compiled with the --with-pgm option: see here - but this doesn't appear to be your issue if you're not seeing "protocol not supported"
  • Using raw pgm requires root privileges because it requires the ability to create raw sockets... but epgm doesn't require that, so it shouldn't be your issue either (I only bring it up because you use the term "pgm/epgm", and you should be aware that they are not equally available in all situations)
  • What actually appears to be the problem in your case is that pgm/epgm requires support along the network path. In theory, it requires support out to your router, so your application can send a single message and have your router send out multiple messages to each client, but if your server is aware enough, it can probably send out multiple messages immediately and bypass this router support. The problem is, as you correctly guessed, trying to do this all on one host is not supported.

So, you need different hosts for client and server.

0
On

Another bit to be aware of is that some virtualization environments--RHEV/Ovirt and libvirt/KVM with the mac_filter option enabled come to mind-- that, by default, neuter one's abilities via (eb|ip)tables to utilize mcast between guests. With libvirt, of course, the solution is to simply set the option to '0' and restart libvirtd. RHEV/Ovirt require a custom plugin.

At any rate, I would suggest putting a sniffer on the network devices on each system you are using and watching to be sure traffic that is exiting the one host is actually visible on the other.