Search Unity

Detect in use or free networking ports?

Discussion in 'Multiplayer' started by TheLastVertex, Jan 22, 2019.

  1. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    I am running multiple servers on a single machine (AWS) and need to assign each server to use a different network port in the Network Manager. If they use the same port (default 7777 as example) you get the following Unity error:

    "Cannot open socket on ip {*} and port {7777}; check please your network, most probably port has been already occupied".

    The plan was to detect which ports were in use, then compare them to my port range and see which were available to assign to the network manager. Unfortunately I've tried multiple ways to detect which ports are in use but none of them seem to pick up on port 7777 being used by Unity.

    Code (CSharp):
    1. using System.Net;
    2. using System.Net.NetworkInformation;
    3.  
    4. IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
    5. IPEndPoint[] tcpEndPoints = properties.GetActiveTcpListeners();
    6. IPEndPoint[] udpEndPoints = properties.GetActiveUdpListeners();
    7. TcpConnectionInformation[] activeEndPoints = properties.GetActiveTcpConnections();
    8.  
    9. //Check port for each etc
    10. tcpEndPoints.Port
    11. udpEndPoints.Port
    12. activeEndPoints.LocalEndPoint.Port
    13.  
    Checking the ports of any, or all of the above never shows port 7777 as in use.

    Only alternatives I've seen is to keep track of what ports I've used manually, but I don't have any way to track this that the server would be able to use.

    Another way would be to manually assign ports via command line arguments for each potential server instance that will run. I'd rather not do this as I don't want to have to set up 50 plus command line preferences or worry about making sure I have enough set for the amount of server instances I'm going to be running.

    Anyone know a way to detect what ports are in use?
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'd probably run 'netstat -l' and a liberal dose of regex.

    My actual method though is I have a master server that manages all the other servers and keeps track of everything, since the other servers in my case can actually be on different physical servers.
     
  3. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    I'll look into this. Thank you.

    I had something similar before I started using Amazon GameLift.

    From what I've seen with GameLift its the opposite of what I was anticipating. I was expecting the GameLift SDK would tell me what ports were available and I'd assign that to the NetworkManager, but it looks like I have to tell it which port I want to use along with assigning it to NetworkManager (I'm going to look into this again just to make sure I didn't interpret this incorrectly).

    Between the two backup options I think I would probably resort to passing in command line arguments since they already have a general mechanism for doing that.
     
  4. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    I came across some information regarding socket servers for .Net. Apparently passing in a port of "0" will auto use a free port and not actually port zero.

    Now, sadly this doesn't appear to work as passing in zero to the network manager results in it remaining set to zero after the server starts.

    But this got me thinking. Is the port number indicated in the Network Manager the actual port that is being used? The reason I ask is because I set it to "7777". Yet "7777" is not detected as in use.

    If I use the pseudo code above to check available tcp, udp, and active connections both before and after the server has started I get a different amount of in use ports. I always get 3 more in use after the server has started. This would make sense, 1 flag for udp, 1 for tcp, and 1 for active connections.

    I also decided to try and set the Network Manager port number to one that should already be in use. Doing so does not cause the Unity error regarding in use ports as it did for using 7777 twice.

    Maybe this is why my port check is failing? I'm expecting it to match the number I pass into the Network Manager, but perhaps under the hood this is being changed?
     
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Oh sorry, I haven't tried gamelift. Perhaps you could have your servers self report to a central server what port they choose to use, and when a server starts up they check with that central server for what it thinks is available?
     
  6. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    Looks like I misspoke on setting the Network Manager port to "0".

    Setting the Network Manager port to "0", starting the server, then asking the network manager what port it is set to will tell you it is still 0.

    What I failed to test initially was whether this causes the server error when multiple instances are run and set to port 0. The answer is no. No port in use error is triggered and the server appears to start fine.

    So this seems to imply "0" will auto assign a port, but the problem is that NetworkManager.networkPort is not the actual port that is being used....?

    Is there a way to find the real port number out?

    Yes, this is a possible backup solution.
     
  7. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    I did a couple further tests and setting the Network Manager port to 7777 results in the UDP port 24862 being used. It's not clear to me why the numbers being reported by dot Net and Unity are different. If anyone knows please feel free to share.

    Since the system and unity are reporting different numbers I don't know an accurate way to determine which ports are free or in use.

    As such I have decided to use the backup option and set the port numbers via command line arguments. This isn't dynamic but thankfully only takes a minute to setup and I only need to do it once.

    This way I can just call:
    myGame.exe -port ####

    Thankfully I can set each executable and command line pair to only be able to run once per instance but still allow multiple.

    Such as:
    myGame.exe -port 7777
    myGame.exe -port 7778
    myGame.exe -port 7779

    This way if the first executable is already running with 7777 in use, it'll run the second one with 7778.

    Code below in case it's useful to anyone in the future.

    Code (CSharp):
    1.  
    2. //Gets a command line argument
    3. public string GetCommandLineArgument(string name)
    4. {  
    5.     var args = System.Environment.GetCommandLineArgs();
    6.     for (int i = 0; i < args.Length; i++)
    7.     {
    8.         if (args[i] == name && args.Length > i + 1)
    9.         {
    10.             return args[i + 1];
    11.         }
    12.     }
    13.     return null;    
    14. }
    15.  
    16. //Sets the network manager port as indicated in the command line arguments
    17. //Defaults to port 7777 if no port is found
    18. public void GetPortFromCommandLineArguments()
    19. {
    20.     int port = 0;
    21.  
    22.     //Get the port from command line argument
    23.     string commandLinePort = GetCommandLineArgument("-port");
    24.  
    25.     //Convert to int
    26.     if (int.TryParse(commandLinePort, out port))
    27.     {
    28.         if(port != 0)
    29.         {  
    30.             //Assign acquired port to network manager            
    31.             Debug.Log("Successfully acquired Port number from command line arguments: " + port);
    32.             networkManager.networkPort = port;
    33.         }
    34.         else
    35.         {
    36.             Debug.Log("Port set to default: " + networkManager.networkPort);
    37.         }
    38.      
    39.     }
    40.     else
    41.     {
    42.         Debug.Log("Failed to acquired Port number from command line arguments: " + port);
    43.     }
    44. }
    45.  
     
    orangetech likes this.