Author Topic: Pinging game servers  (Read 1133 times)

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Pinging game servers
« on: June 20, 2017, 11:01:22 PM »
I've been searching through the forum and have found a few threads talking about Pinging game servers from a Lobby to get their latency but I'm stuck and am hoping someone can help me see what mistake I've made.

- Here is what my code looks like
  1. public void SetupServer(){
  2. udpPort = UnityEngine.Random.Range(10000, 40000);
  3.         if (TNServerInstance.Start(5127, udpPort, null, TNServerInstance.Type.Tcp, Tools.ResolveEndPoint("xx.xxx.xx.xx:5129")))
  4.         {
  5.             TNManager.Connect();
  6.         }
  7. }
  8.  
  9. void OnConnect(bool result, string message)
  10.     {
  11.         if (result)
  12.         {
  13.             TNManager.JoinChannel(1, null, false, 5128, null);
  14.         }
  15.         else
  16.         {
  17.             LoadingScreen.Instance.HideLoadingScreen();
  18.             MessageWindow.DisplayMessageWindow(message);
  19.         }
  20.     }
  21.  
  22. private void OnJoinChannel(int channelID, bool success, string message)
  23.     {
  24.         if (success)
  25.         {
  26.             if (TNManager.isHosting)
  27.             {
  28.                 TNManager.Instantiate(1, "NetworkControllerCreate", "NetworkController", false);
  29.                 TNManager.SetPlayerLimit(4); // Only allow 4 players in an online match
  30.                
  31.                 // Make it possible to use UDP using a random port
  32.                 if (!TNServerInstance.isLocal && TNManager.isHosting)
  33.                     TNManager.StartUDP(udpPort);
  34.             }
  35.         }
  36.         else
  37.         {
  38.             LoadingScreen.Instance.HideLoadingScreen();
  39.             MessageWindow.DisplayMessageWindow(message);
  40.         }
  41.        
  42.     }
  43.  

I then attach the udpPort to my server name and parse it out when accessing in my serverBrowser script:
  1. public void UpdateServerList()
  2.     {
  3.         Debug.Log("Updating server list");
  4.  
  5.         // Clean out previous items
  6.         foreach (Transform child in Content)
  7.         {
  8.             GameObject.Destroy(child.gameObject);
  9.         }
  10.  
  11.         pingDictionary.Clear();
  12.  
  13.         // List of discovered servers
  14.         TNet.List<ServerList.Entry> list = TNLobbyClient.knownServers.list;
  15.  
  16.         // Server list example script automatically collects servers that have recently announced themselves
  17.         for (int i = 0; i < list.size; ++i)
  18.         {
  19.             //Debug.Log("Server " + i);
  20.             TNet.ServerList.Entry ent = list[i];
  21.  
  22.             var go = Instantiate(ServerListOption, Vector3.zero, Quaternion.identity, Content);
  23.             var listOption = go.GetComponent<ServerListOption>();
  24.  
  25.             //var serverDetails = JsonUtility.FromJson<ServerDetails>(ent.name);
  26.             var serverDetails = ent.name.Split('|');
  27.  
  28.             listOption.Ip = ent.externalAddress.ToString();
  29.             listOption.Name.text = serverDetails[0];
  30.             listOption.GameType.text = serverDetails[1];
  31.             listOption.Map.text = serverDetails[2];
  32.             int udpPort = int.Parse(serverDetails[3]);
  33.             listOption.PlayerCount.text = ent.playerCount.ToString() + "/4";
  34.  
  35.             pingDictionary.Add(ent.externalAddress, listOption.Ping);
  36.  
  37.             TNManager.Ping(Tools.ResolveEndPoint(ent.externalAddress.Address.ToString(), udpPort), PingCallback);
  38.            
  39.         }
  40.     }
  41.  

However I always get the error:"The socket is null. Did you forget to call UdpProtocol.Start()?"

I'm calling TNManager.StartUDP with the same port number that my ServerBrowser script then tries to use when pinging the game server....
I'm using TNTcpLobbyClient, do I need to be using TNUdpLobbyClient instead?
I have my Lobby server hosted on Amazon Web Services

Any other ideas what I might be doing wrong?

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Pinging game servers
« Reply #1 on: June 21, 2017, 03:13:29 AM »
You're binding your local gameserver to udpPort (TNServerInstance.Start). On your local client, you connect, join a channel, then attempt to bind your local client to the same udpPort (TNManager.StartUDP). This should cause an exception which should be output to Unity's console. The call should return false if the socket is ever null (always check your return values!).

Additionally, your call to Tools.ResolveEndPoint [within TNManager.Ping(...)] passes the same udpPort. It's unlikely every game server that registers itself with the lobby server has the same udpPort, right? ;p (udpPort = Random.Range(...)). You should bind your gameserver's to a known port (like you pass the constant 5127 for TCP, pass 5128 for UDP). Only the client should bind to the random port.

A few modifications to the source you provided and this should work for you:
Start your game server with a constant UDP port:
TNServerInstance.Start(5127, 5128, null, TNServerInstance.Type.Tcp, Tools.ResolveEndPoint(...))
Bind your client to the random UDP port:
TNManager.StartUDP(udpPort);
Ping each server's constant UDP port:
TNManager.Ping(Tools.ResolveEndPoint(ent.externalAddress.Address.ToString(), 5128), PingCallback);

A minor optimization:
TNManager.Ping(new IPEndPoint(ent.externalAddress.Address, 5128), PingCallback);


Also, I don't know if Amazon Web Services will support UDP. I've never used any Amazon service so I dunno.

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Pinging game servers
« Reply #2 on: June 21, 2017, 03:04:19 PM »
Forgive my ignorance as I'm a TCP vs UDP and ports noob.

So I tried to follow your instruction and still am out of luck, here is what I have:

  1. public void SetupServer()
  2.     {
  3.        
  4.         if (TNServerInstance.Start(5127, 5128, null, TNServerInstance.Type.Tcp, Tools.ResolveEndPoint("xx.xxx.xx.xx:5129")))
  5.         {
  6.             TNManager.Connect();
  7.         }
  8.     }
  9.  
  10. public void SetupClient(string ip)
  11.     {
  12.  
  13.         if (ip == "")
  14.             ip = directConnectIp.text;
  15.  
  16.         // Connect to the remote server
  17.         TNManager.Connect(ip, 5127);
  18.     }
  19.  
  20.     private void OnJoinChannel(int channelID, bool success, string message)
  21.     {
  22.         if (success)
  23.         {
  24.             if (TNManager.isHosting)
  25.             {
  26.                 TNManager.Instantiate(1, "NetworkControllerCreate", "NetworkController", false);
  27.                 TNManager.SetPlayerLimit(4); // Only allow 4 players in an online match
  28.             }
  29.         }
  30.         else
  31.         {
  32.             LoadingScreen.Instance.HideLoadingScreen();
  33.             MessageWindow.DisplayMessageWindow(message);
  34.         }
  35.        
  36.     }
  37.  
  38. void OnConnect(bool result, string message)
  39.     {
  40.         if (result)
  41.         {
  42.             TNManager.StartUDP(UnityEngine.Random.Range(10000, 40000));
  43.             TNManager.JoinChannel(1);
  44.         }
  45.         else
  46.         {
  47.             LoadingScreen.Instance.HideLoadingScreen();
  48.             MessageWindow.DisplayMessageWindow(message);
  49.         }
  50.     }
  51.  

And inside my serverBrowser.cs
  1. TNManager.Ping(new IPEndPoint(ent.externalAddress.Address, 5128), PingCallback);
  2.  

When you say "Only the client should bind to the random port.", should I then in my OnConnect method wrap the StartUDP in a (!isHosting) conditional?
Also TNManager.StartUDP(UnityEngine.Random.Range(10000, 40000)); is returning True for me.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Pinging game servers
« Reply #3 on: June 21, 2017, 08:53:21 PM »
I think the issue is that you're calling Ping before StartUDP.
TNManager.StartUDP actually does two things:
1. Initialize the UDP protocol (underlying socket binding & TNet processing)
2. Notify the gameserver that you're now able to use UDP
Obviously step 2 only occurs if you're connected to a gameserver, but it's important to note that step 1 will occur regardless.
So, in your case, where you're just interested in getting a ping from a bunch of gameservers before actually joining one, you can call TNManager.StartUDP outside of OnNetworkConnect. Perhaps a good place could be your server browser's Start() method?

Just make sure you call TNManager.StartUDP a second time when you actually connect to a gameserver (if you want to use UDP - not at all necessary).

Also: no, you don't need to wrap StartUDP in any conditional. Actually, a tno.isMine might be necessary if your OnConnect handler gets called when remote clients connect too.

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Pinging game servers
« Reply #4 on: June 22, 2017, 12:14:39 AM »
Thank you, I was able to get it to respond to my Ping by adding TNManager.StartUDP(UnityEngine.Random.Range(10000, 40000)); to the Start method of my serverBrowser script.

I did notice now that after I connect to a game I get  the error
Quote
The object was used after being disposed. (Game Client)
UnityEngine.Debug:LogError(Object)
TNet.UdpProtocol:Error(IPEndPoint, String) (at Assets/TNet/Common/TNUdpProtocol.cs:420)
TNet.UdpProtocol:OnReceive(IAsyncResult) (at Assets/TNet/Common/TNUdpProtocol.cs:222)
System.Net.Sockets.Worker:ReceiveFrom()

I tried adding TNManager.StopUDP() to my OnDestroy of my ServerBrowser script (as it gets destroyed when the player connects to a match) but that doesn't seem to help.

Also, I am calling TNManager.StartUDP(UnityEngine.Random.Range(10000, 40000)); in my OnConnect event method, is this an instance where I want to use my static port of 5128 instead of random?

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Pinging game servers
« Reply #5 on: June 22, 2017, 04:25:01 PM »
I dunno. I'd place a breakpoint on TNUdpProtocol.cs:222 and see which object is null.
Only thing I can think of is that you're calling StopUDP (or StartUDP a second time) after sending a Ping but before receiving the response. I'd think that closing the Socket (as is done in those calls) would unbind the Socket and remove its OnReceive callbacks immediately, but I suppose there could be a race condition.

I wonder if ArenMook can make sense of this.

And no, you should always use a random port for the client. Only servers get constant ports.

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Pinging game servers
« Reply #6 on: June 23, 2017, 12:54:43 AM »
Thanks for your help, after some blind tinkering the error no longer pops up. I removed a TNManager.StartUDP I was calling in my OnConnect method and now only call it the 1 time inside my server browser.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Pinging game servers
« Reply #7 on: June 27, 2017, 11:58:44 AM »
Sounds like you solved it correctly. StartUDP is only used to allow for UDP (SendQuickly) traffic to work between client and server after a connection has been established, and isn't used for pinging the server.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Pinging game servers
« Reply #8 on: June 27, 2017, 02:41:23 PM »
Wait, what? The question was about pinging a gameserver before connecting to it. Like on most server browsers, you can see your ping to each server before joining.
UDP is used for that. StartUDP is used to initialize UDP clientside. If there's no connection to the gameserver then it won't send the RequestActivateUDP packet but still initialize the UdpProtocol.

Did you misunderstand the post or am I misunderstanding the "proper" way of doing this?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Pinging game servers
« Reply #9 on: July 06, 2017, 06:08:42 AM »
Let me rephrase the end of my last post: If using StartUDP after connecting, it's used to activate UDP traffic between the client and server, provided the server has UDP enabled. In this case, starting UDP is not used for pinging the server, but for communication between the client and server.