How do ports get handled when running multiple server processes per instance?


I've been reading through the docs, but I'm not clear on how GameLift handles multiple server processes per instance with respect to network ports.

Everything I've read and the videos I've watched are all setup for a port to be entered, but I would expect that each independent game server process would need to run on different ports while sharing an instance to avoid port collisions. (Eg: Server 1 runs on ports 2101-2105, Server 2 runs on ports 2106-2110, Server 3 runs on ports 2111-2115, etc) Additionally, this information would have to be passed to the server executable in some manner (command-line args or config file modification).

Can someone clarify how this works?

asked 6 years ago29 views
9 Answers
Accepted Answer

Hello there, apologies for the delay getting back to you -

ProcessReady & ProcessParameters

Whenever your game server process launches and calls ProcessReady() in the GameLift Server SDK, you pass ProcessParameters into that call. Those ProcessParameters contain a parameter that tells GameLift what port that process is listening to for player connections. It also contains a parameter to tell GameLift where the server logs will be written to so GameLift can collect those for you later to help with debugging. More details are documented here:

  • C++ SDK Guide
  • C# SDK Guide Now, you might be asking yourself "well, how does my server process know what port it should use when contacting GameLift"? There are two options here depending on how your server process works.

Option 1: Your Server Process Auto-Detects the Port

Some game servers will automatically detect the port they should use by trying one, seeing if it's in use and if so, trying another. In your example above, this would mean Server 1 starting with port 2101. No other servers are running, so Server 1 uses port 2101. Server 2 starts and tries port 2101. Unfortunately, port 2101 is in use, so Server 2 tries 2106 which is not in use, so Server 2 uses port 2106. Both Server 1 and Server 2 would communicate their selections to GameLift as part of the ProcessParameters in the ProcessReady call.

If your game server auto-detects the port as I describe, when you configure the multi-process setup in the fleet, you can simply tell GameLift to run 3 identical processes, for example:

  • C:\game\server.exe, +some_args_here, 3 GameLift will start 3 server.exe processes, each of which will auto-detect their ports and update GameLift.

Option 2: Your Server Process Is Told the Port

If your game server needs to be told the port it should listen to when you launch it, you can solve this by telling GameLift to launch 3 server processes, each with slightly different command line arguments. You would do this as part of fleet creation when configuring the multi-process runtime configuration. For example:

  • C:\game\server.exe, +port = 2101, 1
  • C:\game\server.exe, +port = 2106, 1
  • C:\game\server.exe, +port = 2111, 1 GameLift will start 3 server.exe processes but will pass slightly different command-line arguments to each, in this case, containing a different port. Your game server would then take that port setting and give it back to GameLift as part of the ProcessReady call later on. GameLift then knows which server process is expecting traffic on which port.

Fleet Ports

One thing to remember to do is to update your fleet with the inbound port settings that you have your server processes listening on. If you forget to do this, no outside player traffic will make its way to your servers, even though they are listening.

You can manage the open ports on your fleet in either the GameLift Management Console or by making API calls to UpdateFleetPortSettings:

Hopefully this gets you going! If you would like to learn a bit more about how to configure multi-process in GameLift here is a handy link:

answered 6 years ago

How would you pass the port you want your server process to use through the console, just write '+port = 2101' in the text box for Launch Parameters? Also in your c++ is this value passed in argv[] to main?

answered 5 years ago

Yes, you have the right idea. You would include the parameters right in the launch parameters in the console, just as you would if launching your game server locally. GameLift will use that exact launch path you provide when running your server executable. It would then be up to your process to properly parse and handle relevant command line arguments.

answered 5 years ago

How can you tell if a port is "in use"? for your Option 1?

answered 2 years ago

You can see an example in code in threads like this:

Typically you have code in the form:

  • You have something that sets up a port range to use (ie ports 3900-4000), where your range > then the number of processes you are launching on the instance
  • On start up then:
    • Call OS code to find open port(s) in your chosen range.
    • Server tries to bind to port
      • If that fails, then try another port in your list
      • Otherwise, then report that port to GameLift in ProcessReady
answered 2 years ago

In GameLift it will be able to use the exact boot path you specify when running the server executable. It will then be the responsibility of your process to properly analyze and handle arguments and their important commands. Sucess on project! Thanks

answered 2 years ago

Hi - if it is helpful after much trial and error, if you would like your servers to auto-allocate ports, I'd recommend using file locks. This works across Linux and Windows in Mono etc (unlike mutexes, cross process notifications, readerwriterlocks etc). This also means that once the ports have been allocated you can open and close them without worrying about another process picking them up. I have created a little allocator script for Unity in C#, but it could be translated into other languages.

answered 2 years ago

Hi, I tried creating a routine that checks ports availability in sequence and picks the first that is not locked:

	int32 Count = 0;
	int32 Port = 7777;
	FSystemWideCriticalSection* PortMutex = new FSystemWideCriticalSection(FString::FromInt(Port));
	while (!PortMutex->IsValid() && ++Count < MAX_PORTS_COUNT)
		UE_LOG(LogTemp, Warning, TEXT("Port %d seems occupied. Trying with the next one"), Port);
		delete PortMutex;
		PortMutex = new FSystemWideCriticalSection(FString::FromInt(++Port));

	UE_LOG(LogTemp, Display, TEXT("Found free port %d"), Port);

I used UE4's system wide critical sections, but this behaves differently in Windows and Linux. In Windows this routine works: if a mutex can be obtained, the corresponding port will be used, and this will be locked until the process ends. If the port is busy, the critical section won't be considered valid and I can try with the next ports. But Linux implementation of these critical sections relies on flock(), that is a blocking call. If I flock() a port, the next process trying to get access to that port (ie. the second one) will be stuck on flock(). So @REDACTEDUSER Thank you!

Edit: trying with non blocking call flock(FileHandle, LOCK_EX | LOCK_NB) and checking for errno == EWOULDBLOCK

I'll let you know if I'm lucky!

answered 2 years ago

It works, thank you!

answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions