0

I am using Amazon Gamelift to manage a c++ game server in an Amazon Linux 2 environment. This service will launch multiple instances of the same game server on the same machine at nearly the same time. These processes then report back when they are ready and what port they are bound to. What is the best way to attempt to bind to ports in the same range. For instance, I may choose to use between 1900 and 2100, but I may need 100 processes started up. How do I avoid a ton of collisions as these processes try to all bind to different ports at nearly the same time?

273K
  • 29,503
  • 10
  • 41
  • 64
David
  • 1,648
  • 1
  • 16
  • 31
  • 1
    efficiently select ports - allow OS do it. Do not limit the range between 1900 and 2100. – 273K Jun 28 '22 at 17:31
  • 2
    If you need to bind a server within a specific port range, there is no way to let the OS pick the port for you. You would have to bind the server in a loop from the low port to the high port until successful, possibly running the loop multiple times if a collision did occur. Otherwise, you should just pre-configure each server with a specific port instead – Remy Lebeau Jun 28 '22 at 17:34
  • Slightly more efficient way would be to iterate through random port numbers in range 1900..2100 by using RNG seeded with process ID (or any other information unique to the process). – gudok Jun 28 '22 at 17:50
  • 3
    Of course, the parent process doing the spawning or forking could divvy up the ports and pass one to each instance. – Ben Voigt Jun 28 '22 at 17:52
  • Near-duplicate of https://stackoverflow.com/questions/72611183/c-how-do-i-sort-through-an-array-of-port-numbers-on-a-server-to-find-one-that as it uses the same technology just from a different language – Ben Voigt Jun 28 '22 at 17:52
  • @273K It's going to run inside Amazon, so he probably wants to control the range so he only opens up the security group (firewall). – Joseph Larson Jun 28 '22 at 18:29

1 Answers1

0

So I kind of hate that the only answer now is seemingly trying random ports within the unblocked range and retrying on collision, but that is all I seem to have to go on, so I implemented it. Here is the code if its helpful to anyone:

bool MultiplayerServer::tryToBindPort(int port, int triesLeft)
{
    ServerPort = port;
    cout << "Trying Port " << port << "\n";
    triesLeft--;

    Server.Bind(port, [this, port, triesLeft](int errorCode, string errorMessage) 
    {
        cout << errorCode << " : " << errorMessage << "\n";
        cout << "Unable to bind to port: " + port << "\n";
        if(triesLeft <= 0)
        {
            cout << "Ran out of tries to find a good port. Ending \n";
            MyGameLiftServer.TerminateGameSession();
            return;
        }

        tryToBindPort(getRandomPortInRange(), triesLeft);
    });
}

int MultiplayerServer::getRandomPortInRange()
{
    std::random_device rd;
    std::mt19937 mt(rd());
    uniform_int_distribution<int> intDistro(MinPort, MaxPort);
    return intDistro(mt);
}

It seems to work good so far. I plan on opening about 500 ports and then have a max of around 150 server processes started. The chances of a long string of collisions happening then should be fairly small.

David
  • 1,648
  • 1
  • 16
  • 31