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

0

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?

已提問 7 年前檢視次數 644 次
9 個答案
0
已接受的答案

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:

已回答 7 年前
profile picture
專家
已審閱 10 個月前
0

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?

已回答 6 年前
0

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.

已回答 6 年前
0

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

已回答 3 年前
0

You can see an example in code in threads like this: https://forums.awsgametech.com/t/port-in-amazon-console-different-to-port-passed-in-to-processready/9656/7

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
已回答 3 年前
0

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

已回答 3 年前
0

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.

已回答 3 年前
0

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!

已回答 3 年前
0

It works, thank you!

已回答 3 年前

您尚未登入。 登入 去張貼答案。

一個好的回答可以清楚地回答問題並提供建設性的意見回饋,同時有助於提問者的專業成長。

回答問題指南