简体   繁体   中英

Cannot get ReadyReceive pub-sub to work using NetMQ 4.x

I created 2 simple C# Console Projects (.net 4.5.2), added the v4.0.0.1 NetMQ Nuget package to each, loaded each program up into separate Visual Studio 2017 Community Editions, put a breakpoint on the 1 line contained within the OnReceiveReady callback method, started the subscriber program first, then started the publisher program. The ReceieveReady event is not being triggered in the subscriber. What am I doing wrong? Even if I chose subSocket.Subscribe("") then I still didn't get any messages received. Also, removing/modifying the Send/Receive HighWatermarks didn't change things either. Thanks for your help!

Here's the Publisher code:

using System;
using NetMQ;
using NetMQ.Sockets;
using System.Threading;

namespace SampleNQPub
{
    class Program
    {
        static void Main(string[] args)
        {
            var addr = "tcp://127.0.0.1:3004";

            using (var pubSocket = new PublisherSocket())
            {
                Console.WriteLine("Publisher socket binding.");
                pubSocket.Options.SendHighWatermark = 10;
                pubSocket.Bind(addr);

                for (int i=0; i < 30; i++)
                {
                    pubSocket.SendMoreFrame("NQ").SendFrame(i.ToString());
                    Thread.Sleep(1000);
                }

                pubSocket.Disconnect(addr);
            }
        }
    }
}

Here's the Subscriber code:

using System.Threading;
using NetMQ;
using NetMQ.Sockets;

namespace SampleNQSub
{
    class Program
    {
        static void Main(string[] args)
        {
            var addr = "tcp://127.0.0.1:3004";

            using (var subSocket = new SubscriberSocket())
            {
                subSocket.ReceiveReady += OnReceiveReady;
                subSocket.Options.ReceiveHighWatermark = 10;
                subSocket.Connect(addr);
                subSocket.Subscribe("NQ");

                for (int i=0; i < 20; i++)
                {
                    Thread.Sleep(1000);
                }

                subSocket.Disconnect(addr);
            }
        }

        static void OnReceiveReady(object sender, NetMQSocketEventArgs e)
        {
            var str = e.Socket.ReceiveFrameString();
        }
    }
}

Ok, this is a gotcha question in the NetMQ world and I just figured it out. You MUST setup a NetMQPoller that will wind up calling every ReceiveReady callback which you have added to it (NetMQPoller).

Here is the corrected code which will at least (ie, ReceiveFrameString still only getting the "NQ" part but that's just another method call to fix) get the ReceiveReady event triggered:

using System.Threading;
using System.Threading.Tasks;
using NetMQ;
using NetMQ.Sockets;

namespace SampleNQSub
{
    class Program
    {
        static void Main(string[] args)
        {
            var addr = "tcp://127.0.0.1:3004";

            NetMQPoller poller = new NetMQPoller();

            using (var subSocket = new SubscriberSocket())
            {
                subSocket.ReceiveReady += OnReceiveReady;
                subSocket.Options.ReceiveHighWatermark = 10;
                subSocket.Connect(addr);
                subSocket.Subscribe("NQ");

                poller.Add(subSocket);
                poller.RunAsync();

                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(1000);
                }

                subSocket.Disconnect(addr);
            }
        }

        static void OnReceiveReady(object sender, NetMQSocketEventArgs e)
        {
            var str = e.Socket.ReceiveFrameString();
            e.Socket.ReceiveMultipartStrings();
        }
    }
}

I noticed that the authors of NetMQ decided in 4.x to take care of the Context object internally so the user wouldn't have to bare the burden of managing it. It would be nice also if they could hide this "polling pump" code from the user as well for the most simple use case.

As a comparison, take a look at the subscriber using NodeJS (with the zmq library) utilizing the Publisher console app I posted above (save this code to sub.js and, in a Windows console, type 'node sub.js'):

var zmq = require('zmq'), sock = zmq.socket('sub');

sock.connect('tcp://127.0.0.1:3004');
sock.subscribe('NQ');
console.log('Subscriber connected to port 3004');

sock.on('message', function() {
    var msg = [];
    Array.prototype.slice.call(arguments).forEach(function(arg) {
        msg.push(arg.toString());
    });

    console.log(msg);
});

So where's the poller pump mechanism in this? (Answer: I don't care! I just want the messages supplied to me in a callback that I register. [Obviously, tongue-in-cheek. I get that a NetMQPoller is versatile and handles more complex issues, but for basic "give me a message in a callback when it arrives", it would be nice if it were handled internally by the library.])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM