2

I have a problem with ROUTER-ROUTER communication with NetMQ.

Two applications, Client and Server. Both using ROUTER sockets. Client ROUTER socket is not setting it's identity explicitly, only Server.

After the connection established first time, messages are routed from client (ROUTER) to server (ROUTER). But as soon as client calls Disconnect() and then Connect() again (after a very short time, i.e. 10 msec), the server is not receiving messages any more.

What is interesting, that reconnection works fine if ZeroMq C# lib is used.

Is it a known issue or I'm doing something wrong here?

Minimal code to reproduce the issue:

  public class PureNetMQ
  {
    private static readonly byte[] ServerIdentity = {1, 2, 3};
    private static readonly byte[] ClientIdentity = {1, 2, 4};
    private static readonly string Address = "tcp://127.0.0.1:5000";

    private static void Main(string[] args)
    {
      var cancellationTokenSource = new CancellationTokenSource();
      Task.Factory.StartNew(_ => RunServer(cancellationTokenSource.Token), cancellationTokenSource.Token, TaskCreationOptions.LongRunning);
      Thread.Sleep(TimeSpan.FromSeconds(2));

      RunClient();

      Console.WriteLine("Done");
      Console.ReadLine();
      cancellationTokenSource.Cancel(true);
    }

    private static void RunClient()
    {
      using (var context = NetMQContext.Create())
      {
        using (NetMQSocket socket = context.CreateRouterSocket())
        {
          //socket.Options.Identity = Guid.NewGuid().ToByteArray();
          //socket.Options.RouterMandatory = true;
          socket.Options.Linger = TimeSpan.Zero;

          socket.Connect(Address);

          Thread.Sleep(TimeSpan.FromSeconds(2));

          socket.SendMore(ServerIdentity);
          socket.SendMore(Encoding.UTF8.GetBytes(""));
          socket.Send(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
          Console.WriteLine("Message sent...");

          socket.Disconnect(Address);
          Thread.Sleep(TimeSpan.FromSeconds(5));
          Console.WriteLine("Disconnected");

          //socket.Options.Identity = Guid.NewGuid().ToByteArray();
          socket.Connect(Address);
          Thread.Sleep(TimeSpan.FromSeconds(5));
          Console.WriteLine("Reconnected");


          socket.SendMore(ServerIdentity);
          socket.SendMore(Encoding.UTF8.GetBytes(""));
          socket.Send(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
          Console.WriteLine("Message sent...");

          Thread.Sleep(TimeSpan.FromSeconds(5));
        }
      }
    }

    private static void RunServer(CancellationToken token)
    {
      using (var context = NetMQContext.Create())
      {
        using (var socket = context.CreateRouterSocket())
        {
          socket.Options.Identity = ServerIdentity;
          //socket.Options.RouterMandatory = true;
          socket.Options.Linger = TimeSpan.Zero;

          socket.Bind(Address);

          while (!token.IsCancellationRequested)
          {
            var message = socket.ReceiveMessage();

            for (var i = 2; i < message.FrameCount; i++)
            {
              Console.WriteLine("Message: {0}", Encoding.UTF8.GetString(message[i].Buffer));
            }
          }
        }
      }
    }
  }
iiwaasnet
  • 51
  • 1
  • 8
  • Based on your description, it sounds like an edge case in the NetMQ implementation. Does it work in a test case if you *do* set the client identity explicitly? My first guess is that the client is changing its identity between connections and the server doesn't cope with that appropriately. I'd try setting that identity and, separately, artificially lengthening the time before reconnecting to see if that allows the server socket enough time to "forget". If either (or both) of those work, then you've found your answer. – Jason Aug 11 '15 at 13:56
  • @Jason Thanks a lot for reply! I posted the code to reproduce the issue. Basically, I guess client is not required to have an Identity, until you would like to route replies back (which is not my case). As well, if identity is not assign explicitly, it will be provided by the router, to which you connect. Anyway, whatever I was doing, the second message is not received by the server. When client-side ROUTER socket is assigned an Identity, then it even blocks trying to send second message (Message sent... text never printed). Same code works fine with **clrzmq**. – iiwaasnet Aug 11 '15 at 14:54
  • what version of netmq are you using? – somdoron Aug 11 '15 at 15:51
  • can you add a bug in https://github.com/zeromq/netmq? – somdoron Aug 11 '15 at 15:54
  • @somdoron [Submitted](https://github.com/zeromq/netmq/issues/372), thank you! **VER:** 3.3.0.11 – iiwaasnet Aug 11 '15 at 16:57
  • just added PR to solve it. – somdoron Aug 11 '15 at 17:01

1 Answers1

4

Zeromq had a fix for this that was not ported to NetMQ yet. I ported it now, you can use it from:

https://github.com/somdoron/netmq

It soon should be merged to master soon: https://github.com/zeromq/netmq/pull/373

Also another issue that is relevant and was solved in ZeroMQ is the handling of duplicate identities in router. by default the second socket with the identity is ignored. ZeroMQ have the handover option, if enabled the new socket take over the old one. You should consider using this or port it to netmq as well.

https://github.com/zeromq/libzmq/pull/729/files https://github.com/zeromq/libzmq/pull/731

somdoron
  • 4,653
  • 2
  • 16
  • 24