ZeroMQ PUB / C# SUB not working when subscriber started before publisher

Viewed 1878

When running the ZeroMQ basic PUB / SUB C# samples they are working for me if I start the publisher first, but not if I start the subscriber first. When I do that the subscriber starts, but never receives any data. From what I have read, I thought that I should be able to start the processes in either order.

I am using the ZeroMQ 4.1.0.26 package from nuget in .NET 4.6, x64 apps. These are running on Windows. I am running both apps on the same machine.

Here are is the code I am running (which is a simplified version of the sample from the ZeroMQ tutorial).

Subscriber:

    static void Main(string[] args)
    {
        var endpoint = "tcp://127.0.0.1:5556";

        // Socket to talk to server
        using (var context = new ZContext())
        using (var subscriber = new ZSocket(context, ZSocketType.SUB))
        {
            Console.WriteLine("I: Connecting to {0}…", endpoint);
            subscriber.Connect(endpoint);

            // Subscribe to zipcode
            string zipCode = "90210 ";
            Console.WriteLine("I: Subscribing to zip code {0}…", zipCode);
            subscriber.Subscribe(zipCode);

            while(true)
            {
                using (var replyFrame = subscriber.ReceiveFrame())
                {
                    string reply = replyFrame.ReadString();
                    Console.WriteLine(reply);
                }
            }
        }
    }

Publisher:

    static void Main(string[] args)
    {
        using (var context = new ZContext())
        using (var publisher = new ZSocket(context, ZSocketType.PUB))
        {
            var address = "tcp://*:5556";
            Console.WriteLine("I: Publisher.Bind'ing on {0}", address);
            publisher.Bind(address);

            // Initialize random number generator
            var rnd = new Random();
            while (true)
            {
                // Get values that will fool the boss
                int zipcode = 90210;
                int temperature = rnd.Next(-55, +45);

                // Send message to all subscribers
                var update = string.Format("{0:D5} {1}", zipcode, temperature);
                using (var updateFrame = new ZFrame(update))
                {
                    publisher.Send(updateFrame);
                }

                Thread.Sleep(1000);
            }
        }
    }

Edit

Following suggestions in proposed answers below I tried:

  • Using an explicit IP address: this made no difference
  • Removing the subject filtering: this made no difference
  • Creating new AnyCPU (instead of x64) projects: this made no difference
  • Trying other languages: this was interesting!

Using Python equivalent publishers and subscribers:

  • The Python subscriber works when started before the publisher, when connecting to either the Python publisher or the C# publisher.
  • The C# subscriber does not work when started before the publisher, regardless whether it is connecting to the Python or C# publisher.

So it looks like there is something wrong with the C# subscriber code.

QUESTION:

  • Is there something wrong with my sample code ( latest version below )?

  • Or is it a problem with the ZeroMQ .NET library?

Here is the Python subscriber which worked correctly:

import sys
import zmq

#  Socket to talk to server
context = zmq.Context()
socket  = context.socket( zmq.SUB )

print( "Python: Collecting updates from weather server" )
socket.connect( "tcp://localhost:5556" )

socket.setsockopt_string( zmq.SUBSCRIBE, "" )

while True:
    string = socket.recv_string()
    zipcode, temperature = string.split()
    print( zipcode + " " + temperature )

Here is the latest equivalent ( non-working ) version of the C# subscriber:

static void Main(string[] args)
{
    // Socket to talk to server
    using (var context = new ZContext())
    using (var socket = new ZSocket(context, ZSocketType.SUB))
    {
        Console.WriteLine("C#: Collecting updates from weather server");
        socket.Connect("tcp://localhost:5556");
        socket.Subscribe("");

        while (true)
        {
            using (var replyFrame = socket.ReceiveFrame())
            {
                string reply = replyFrame.ReadString();
                Console.WriteLine(reply);
            }
        }
    }
}
1 Answers

If you would follow, step-by-step the flow-chart re-published here, the problem of the PUB/SUB gets highlighted.

Recent ( EoY-2017 ) API v4.x re-engineering efforts have changed some design approaches ( whether the topic-filter gets processed on the SUB-side, as it was since v2.1+, or --as in the newer API versions-- at the PUB-side, reversing the overhead distribution/concentration, exgress-flow buffering+traffic/processing-overhead ), yet, the PUB/SUB order of operations seems to remain the same ( ref. the flow-chart mentioned above ).


Ex-post root-cause isolation testing:

Python SUB works correctly, my C# one does not. Not clear WHY:

Thanks for active code-re-testing, that helped to move a few steps forwards in the root-cause discrimination.

Now let's focus on the WHY:

ZeroMQ has typically two abstract layers, the ZeroMQ internal one, implementing the core-facilities of the framework, as defined in the ZeroMQ protocol RFC-specifications. This is the part, that is responsible for all RFC-defined interactions to become compliant and cross-compatible, so as to serve in the ZeroMQ published manner.

The other layer is constituted by a "foreign"-language wrapper / API binding, that helps other languages, non-native to the ZeroMQ internal code, to use the services exposed by the ZeroMQ API for any particular 3rd-party language mediation, so as the "foreign"-worlds get chance to call the services, that are implemented by the library, inside the world of the internal ZeroMQ layer.

So, the discrepancy was isolated using the python SUB-probe ( which worked well, as defined ) to the C# language binding, where the SUB-probe remained not working.

As Dijkstra noted on testing, a fact that some tests were working as expected does not mean there are no other bugs / errors in the system, there might be some more troubles with the binding, however this positive acknowledgement from python SUB-client showed, that ZeroMQ core-services are not those to get blamed for causing the error.


A1: No,

your code seems ok.

A2: Yes,

as explained above, this is the main suspect ATM

Reporting a request to the C# binding maintainers to fix the ZeroMQ non-conformant behaviour, documented in full details as observed and re-tested above, is the best next step to help the non-compliant C# binding get working hassle-free.

Related