zeromq / netmq

A 100% native C# implementation of ZeroMQ for .NET
Other
2.96k stars 743 forks source link

StreamSocket does not send empty connect/disconnect message when peers connect/disconnect #1096

Open jens-auer opened 4 months ago

jens-auer commented 4 months ago

Environment

NetMQ Version:    4.0.1.13
Operating System: Windows 10
.NET Version: 8

Expected behaviour

In ZeroMQ, stream sockets send an empty message for peer connect / disconnect:

When a connection is made, a zero-length message will be received by the application. Similarly, when the peer disconnects (or the connection is lost), a zero-length message will be received by the application.

This seems not to be the case for NetMQ. The following code blocks on the first s1.ReceiveMultipartBytes()

[TestClass]
public class TestStreamSocket
{
    [TestMethod]
    public void TestConnectDisconnectMessages()
    {
        var s1 = new StreamSocket();
        var port = s1.BindRandomPort("tcp://127.0.0.1");

        var s2 = new StreamSocket();
        s2.Connect($"tcp://127.0.0.1:{port}");

        var connectMsg = s1.ReceiveMultipartBytes();
        Assert.AreEqual(2, connectMsg.Count);
        Assert.AreNotEqual(0, connectMsg[0].Length);
        Assert.AreEqual(0, connectMsg[1].Length);

        s2.Disconnect($"tcp://127.0.0.1:{port}");
        var disconnectMsg = s1.ReceiveMultipartBytes();
        Assert.AreEqual(2, connectMsg.Count);
        Assert.AreNotEqual(0, connectMsg[0].Length);
        Assert.AreEqual(0, connectMsg[1].Length);
    }
}

ZeroMQ has a socket option ZMQ_STREAM_NOTIFY to enable (=1) or disable this behavior. Default is enabled (=1).

As an example, the following Python code uses libzmq and shows the expected behavior:

import zmq

ctx = zmq.Context()

s1 = ctx.socket(zmq.STREAM)
s2 = ctx.socket(zmq.STREAM)

port = s1.bind_to_random_port("tcp://127.0.0.1")

s2.connect(f"tcp://127.0.0.1:{port}")
connect = s1.recv_multipart()
print(connect)

s2.disconnect(f"tcp://127.0.0.1:{port}")
s2.close()

disconnect = s1.recv_multipart()
print(disconnect)

Output:

[b'\x00\x80\x00\x00)', b'']
[b'\x00\x80\x00\x00)', b'']

Actual behaviour

Steps to reproduce the behaviour

Run above unit test.

drewnoakes commented 4 months ago

Would you be able to make a pull request?

jens-auer commented 4 months ago

I can take a look. Is it possible to use a Monitor to detect a connect / disconnect and get the corresponding identity via socket options?