7

I'm writing a distributed search algorithm in which agents need to listen on a TCP socket for incoming connections. At some point, the agent should bind a free TCP port. Port number is not important but agent should send his/her listening port number to other agents.

I guess this is right way of doing:

socket.bind("tcp://*:0");

Socket binds successfully but then, how do I get the port number that socket's bound to? I can't see any option code in zmq_getsockopt man page returning a port number.

sorush-r
  • 10,490
  • 17
  • 89
  • 173
  • The attribute `socket.LAST_ENDPOINT` should have the resolved bind address. It is also a good idea to use the method [socket.bind_to_random_port](https://pyzmq.readthedocs.io/en/latest/api/zmq.html#zmq.Socket.bind_to_random_port). – Danilo Gómez Dec 07 '20 at 14:52

1 Answers1

20

With Zeromq you use a string to bind or connect. The it starts with the protecol, tcp:// in your case, this is allright. Then you have a '*' which stand for all available devices. Then you end with the port numer :0 in your case.

socket.bind("tcp://*:2424)

Would try to bind at port 2424. If you run man zmq_tcp they advise the port number to be higher than 1024. Basically you should know your portnumber in advance, not after binding. In newer versions 3.2 it is also possible to specify the port :0 or :* then the os will decide where the port is. This can be retrieved with socket.getsockopt() as seen in the next example:

zmq::context_t context(1);
zmq::socket_t sock(context, ZMQ_REP);
char port[1024]; //make this sufficiently large. 
                 //otherwise an error will be thrown because of invalid argument. 
size_t size = sizeof(port);
try{
    sock.bind("tcp://*:*");
}
catch (zmq::error_t&e ){
    cerr << "couldn't bind to socket: " << e.what();
    return e.num();
}
sock.getsockopt( ZMQ_LAST_ENDPOINT, &port, &size );
cout << "socket is bound at port " << port << endl;

This will give the following output for example:

socket is bound at port tcp://0.0.0:53269

So you still have to parse 53269 from the string "tcp://0.0.0.0:53269" hope this helps

hetepeperfan
  • 4,292
  • 1
  • 29
  • 47
  • @soroush You have a kind of a strange typo in your last comment. I think you intended to write "port number". I Don't know if it is possible to let the os decide but I have a look. – hetepeperfan May 22 '13 at 19:38
  • Oops! Sorry about that ;) It's not editable anymore (somebody kill me) So I deleted. It's quiet possible and already an available feature in zmq. [This discussion on github](https://github.com/zeromq/libzmq/pull/238) describes how to do it right. But it's not working with C++. I think it's a bug with C++ port of ZMQ. I've not tested with C yet... – sorush-r May 22 '13 at 19:44
  • @soroush Are you using version 3.2? I used versions 2.x a lot, but according to the C -api (version 3.2) you should use ZMQ_LAST_ENDPOINT it might work if you pass that to socket.get_sockopt(), since the C++ api includes the C api. Also then the string should be tcp://*:* – hetepeperfan May 22 '13 at 20:00
  • @soroush I've updated my answer to meet your criteria better. – hetepeperfan May 22 '13 at 22:11
  • I disaagree with your statement that one should know the portnumber in advance. Even if you check if a certain port is available before binding to it, the port could still become unavailable between your check and the bind attempt. So I prefer your example using `getsockopt`. – jan Aug 07 '14 at 11:57