Question

I want to connect clients to a server using ZeroMQ (java bindings, jzmq), but I need the TCP information badly, for example the TCP/IP address of a client request! The problem is, for being able to announce a service in the network I need to grab the TCP address of a request to be able to redirect clients to that service. The broker is a central "service registry" in that case. However, having ZeroMQ services on both sides, I do not see an option to retrieve that information.

What I do now, is to establish a dummy connection using a standard socket to the broker, after the connection is established I grab the IP address used for this connection and close the connection again. The IP address which has been retrieved is now being used for binding on it using a ZeroMQ socket on a random port.

I think this solution is the ugliest solution ever possible, so: What is a better solution to this problem?

Greetings.

Was it helpful?

Solution

0MQ doesn't provide the address of peers, for a number of reasons. It's also not that useful since what you really want is the endpoint to receive connections on, not the address the connection was made on.

What I usually do, and it's elegant enough, is pass bind a service to an ephemeral port, get a full connection endpoint ("tcp://ipaddress:port") and send that string in some way, either broadcast to peers, to a central registry, etc. along with my service name. Then, peers who want to connect back can take the service name, look up to find my endpoint, and connect back to me.

OTHER TIPS

In ZMQ 4.x, you may get the string property "Peer-Address" or the "Identity" property. http://api.zeromq.org/4-2:zmq-msg-gets

The Identity is set in the other peer before connect(). http://api.zeromq.org/4-2:zmq-setsockopt#toc20

For example,

const char *identityString = "identity";
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REQ);
socket.setsockopt(ZMQ_IDENTITY, identityString, strlen(identityString));
socket.connect("tcp://127.0.0.1:5555");

Then the other side:

while(1)
{
    zmq::message_t request;
    if (socket.recv(&request, ZMQ_NOBLOCK))
    {
        const char* identity = request.gets("Identity");
        const char* peerAddress = request.gets("Peer-Address");
        printf("Received from %s %s\n", peerAddress, identity);
        break;
    }
}

I'm using CppZmq btw, you should be able to find the relevant calls easily.

Digging deeper into the libzmq code, I discovered that the library attaches to every message instance the file descriptor that it was received on.

This worked for me

    int sockfd = zmq_msg_get(&msg, ZMQ_SRCFD);

    sockaddr_in addr;
    socklen_t asize = sizeof(addr);
    getpeername(sockfd, (sockaddr*)&addr, &asize);

    std::cout << inet_ntoa(addr.sin_addr) << ":" << addr.sin_port << std::endl;

Note that the FDs can and will be reused by other connections.

I'm working with version 4.2.1 of the api using the CZMQ binding and I found a solution for my case (ZMQ_STREAM). It works by setting an id before connecting.

The relevant socket option is "ZMQ_CONNECT_RID".

ZMQ api via zmq_setsockopt()

CZMQ api via zsock_set_connect_rid()

Some codes with redacted redacted ips.

const char endpoint1[] = "tcp://1.2.3.4:12345"
const char endpoint2[] = "tcp://5.6.7.8:12345"

zsock_t *stream = zsock_new(ZMQ_STREAM);
zsock_set_connect_rid(stream, endpoint1);
zsock_connect(stream, endpoint1);
zsock_set_connect_rid(stream, endpoint2);
zsock_connect(stream, endpoint2);

Then I get those 2 messages if there is a connection. First frame is the id and second frame is empty on connect/disconnect for ZMQ_STREAM sockets.

[Message1]

[019] tcp://1.2.3.4:12345
[000]

[Message2]

[019] tcp://5.6.7.8:12345
[000] 

Another option is to use the zmq_socket_monitor() or czmq zmonitor. It was one of my first solution but I was looking for something lighter. I was able the get the endpoint that way without setting the id directly on the socket.

The zmonitor zactor make it possible to subscribe to socket events and then it sends a message with 3 frames:

[009] CONNECTED
[002] 14
[021] tcp://127.0.0.1:33445
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top