Get TCP address information in ZeroMQ
Asked Answered
S

4

12

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.

Skald answered 30/1, 2013 at 11:2 Comment(0)
E
7

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.

Ehr answered 30/1, 2013 at 11:11 Comment(2)
Could you explain 'pass bind a service to an ephemeral port, get a full connection endpoint ("tcp://ipaddress:port")' in more detail? I need exactly that. How would you do that? Btw I LOVE 0MQ, thanks for that!!! =)Hindrance
I just posted a more relevant answer and then noticed who posted that one... I must say thanks for your work! I really enjoy working with 0MQ. I learned so much by digging in the code to try understand how it works.Ventriloquist
A
7

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.

Aggravation answered 2/7, 2018 at 6:3 Comment(0)
E
1

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.

Eal answered 1/12, 2020 at 11:13 Comment(0)
V
0

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
Ventriloquist answered 23/2, 2017 at 16:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.