Search code examples
zeromqnetmq

How port allocation is done behind the scenes in zmq?


I have been looking into zmq for a while now and have implemented a simplified poc - to mimic my infrastructure design - using it (specifically using the NetMQ wrapper), with great results.

My situation is this:

In the future I am planning to run multiple clients on a single machine, where each client needs to communicate with a "server" (located on a different machine) via multiple sockets.

I've noticed that for each socket that I declare and open explicity many more are opened internally by zmq and are managed by it.

Edit

binding sockets get a new port allocated in the dynamic range and that is fine,

but although my client connects explicitly to only 2 ports, some 15 ports are allocated for him automatically by zmq.

this, I fear, might eventually lead to a shortage of ports, a situation I very much want to avoid.

The questions:

  1. How does zmq allocates ports intenally and what is the ratio between explicitly declared sockets and the ports zmq openes automatically?

  2. Is there a way for me to control the port allocation programatically, via configuration or by any other means?

  3. How does using a poll affects the ports usage?

Tnx,


Solution

  • When you create a socket on zeromq/netmq on windows a dedicated socket is used to signal between io thread and user thread, this socket take two ports. if you call bind you bind another port with your selected port.

    The dedicated socket is using the dynamic port range (netmq), so if you stay away from that range you will not have any problem.

    Dynamic port range for windows vista and above is 49152 until 65535

    port counting code:

    static void Main(string[] args)
    {
        var id = Process.GetCurrentProcess().Id;
    
        using (var context = NetMQContext.Create())
        {
            List<NetMQSocket> sockets = new List<NetMQSocket>();
    
            NetMQSocket server = context.CreateDealerSocket();
            server.Bind("tcp://localhost:6666");
    
            int i= 0;
            while (true)
            {
                var client = context.CreateDealerSocket();
                client.Connect("tcp://localhost:6666");
    
                sockets.Add(client);
    
                Thread.Sleep(1000);                                       
    
                ProcessStartInfo startInfo = new ProcessStartInfo("NETSTAT.EXE", "-a -o");
                startInfo.RedirectStandardOutput = true;
                startInfo.UseShellExecute = false;
                startInfo.CreateNoWindow = true;
    
                Console.WriteLine("Calculating taken ports...");
    
                Process process  = Process.Start(startInfo);                    
                int portCounter = -7; // start with minus 4 for framework and server socket
    
                while (!process.StandardOutput.EndOfStream)
                {
                    if (process.StandardOutput.ReadLine().Contains(id.ToString()))
                    {
                        portCounter ++;
                    }
                }
    
                Console.Clear();
                Console.WriteLine("{0} sockets takes {1} ports, avg of {2} ports per socket", sockets.Count, portCounter, portCounter / sockets.Count);
                Console.WriteLine("Press enter to create another socket");
    
                Console.ReadLine();
            }
        }
    }