Port in Amazon console different to port passed in to ProcessReady

Have a player setting up sessions directly using createGameSession. My server decides upon a port by looking for a free port before opening up the network connection to client (using mirror) and in the process parameters sent back to gamelift in ProcessReady.

I have tested for free port 2 ways, first by trying to open ports in a specific range until I get an open response, then I close the port and pass back to Mirror and ProcessReady. Alternately I have tested looking through all the ports marked as being used using IPGlobalProperties and selecting one not used there.

However I’m getting some weird results where sometimes a second instance tries to connect to the first. Weirdly when I look at the Console and output logs, where a game server has determined that say port 8002 is the first free one (8000 and 8001 being busy on other servers), and Mirror opening correct port (8002) and ProcessReady being sent the correct port (8002) as indicated in output logs, I will often get the Amazon console saying that the game server is running on port 8001 or 8000, and telling the client to connect to one of these.

I am leaving a lrage gap in time (well 5 seconds) between setting up servers, so I can’t imagine that there is a race condition on the sockets. As the outputs are sending the correct port number to ProcessReady I can’t see why the console shows the wrong port?

In case handy, I find free port using both of these methods (not at some time)

public int findNextFreeSocket(int startingSocket)
{
IPAddress ipAddress = Dns.GetHostEntry(“localhost”).AddressList[0];

    while (true)
    {
        try
        {
            TcpListener tcpListener = new TcpListener(ipAddress, startingSocket);
            tcpListener.Start();
            int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
            tcpListener.Stop();
            Debug.Log("<color=purple>GameLift: </color> found free port " + port);
            return port;
        }
        catch (Exception e)
        {
            Debug.Log("<color=purple>GameLift: </color> found busy port with exception data" + e.ToString());
            startingSocket += 10;
        }
    }

}

public int findNextFreeSocketAlternative(int startingSocket)
{
    List<int> portArray = new List<int>();

    var properties = IPGlobalProperties.GetIPGlobalProperties();

    // Ignore active connections
    var connections = properties.GetActiveTcpConnections();
    portArray.AddRange(from n in connections
                       where n.LocalEndPoint.Port >= startingPort
                       select n.LocalEndPoint.Port);

    // Ignore active tcp listeners
    var endPoints = properties.GetActiveTcpListeners();
    portArray.AddRange(from n in endPoints
                       where n.Port >= startingPort
                       select n.Port);

    // Ignore active UDP listeners
    endPoints = properties.GetActiveUdpListeners();
    portArray.AddRange(from n in endPoints
                       where n.Port >= startingPort
                       select n.Port);

    portArray.Sort();

    for (var i = startingPort; i < UInt16.MaxValue; i++)
    {
        if (!portArray.Contains(i))
        {
            return i;
        }
    +
    return 0;
}

Definitely a race condition of some sort - have been trying all sorts of things, I think what is happening is that I set up my networking which cnages the scene and take a bit of processing. While this is happening, GameLift tries to call the OnStartGameSessionDelegate, and must timeout without receiving a satisfactory response. So in this situation, the server is running and can accept connections, and will also block the socket, however GameLift does not think it’s a valid game session and therefore will not provide a valid player session when requesting. It also means that when a second game session runs, it can easily connect in to the invalidly running previous session on that port, send along an invalid player session (for the old game session) and get in all sorts of trouble.

Could someone confirm if they think this is possible?

Dynamic port allocation and multi-process is tricky. Each process is going to spin up very close in time to each other and race to find a free port and then bind to it. If all the processes hit your socket finding code approximately at the same time, they could all leave with the same ‘free’ port as a port is free until something binds to it ie:

  • Server A starts, thinks port 9600 is free but doesn’t bind to Port immediately
  • Server B starts, also thinks port 9600 is free (nothing is bound to it)
  • Both servers report they are on port 9600 in ProcessReady and hilarity ensues but only one will have an open socket. GameLift cannot determine which process+port any specific message is for at this time.

This is why I prefer static port allocation (but it makes create fleet calls extremely verbose) as each launch configuration can be given its own specific port.

Each process needs a retry loop right, which:

  • Find a free port
  • tries to bind to it
  • repeats until free port is bound to for process
  • and then and only then call ProcessReady

Note: you can change your game session timeouts to cover for your load times if required.

If you use player sessions then you should be able to avoid players connecting on stale ports etc. They should only be able to connect to the active game session they were created for; game sessions are owned by a particular process + port.

So as long as you can guarantee process + port is unique for each server you are launching on a GameLift instance, you should be good.

Yes I’m getting some weird results - it’s odd as it’s definitely my code, because the server jumps by a port incrementer I’m setting, however it’s happening when there’s only one process running. Still lots to try…

I’ve tried meshing with GameLift straight away and then loading the heavy scene after receiving a game start (definitely does not work), now am going to try doing all the heavy scene load and socket grabbing before I even call Init and ProcessReady.

(ignore the below, worked it out)
What are the sort of acceptable timeouts to respond to server if any?

And I can’t see any way of telling a client how long to wait for a timeout, I can poll while going from ACTIVATING to ACTIVE, however is there a way to get a callback or set a suitable timeout somewhere?

Best

Oh - tried setting up my outputs so that all text would log out to a separate file absed on port number, and had a massive realisation!

Could you please confirm - I was working on the assumption that a process is started up when it is requested via CreateGameSession - so that with say 12 concurrent processes specified there would be 0 running when the fleet is set up. Then each CreateGameSession would call into existence a application process.

However it looks to me like each process is started as soon as a fleet is activated, so when I specify 12 concurrent processes, at the beginning 12 separate runtimes begin. This changes everything, and I can suddenly understand the race conditions.

Let me know if I’m wrong in this!

When starting a up a new GameLift managed instance:

  • GameLift launches x versions of your server code (based on your fleet runtime config) concurrently.
  • Each server process starts up and completes setup with GameLift (calls InitSDK/ProcessReady)
    • Lets GameLift know what port its on and that its ready to go
  • Once the server process is fully registered its eligible for a GameSession
  • GameLift begins to place game sessions on ready processes.
  • etc.

So yes all your server processes start at approximately the same time on a brand new instance (there will be slight jitter in launch times due to OS resource provisioning etc).

Pip you are a legend - many thanks for all your help