Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

OnServerDisconnect being called inappropriately - Best way to check if a connection is still active?

Discussion in 'Multiplayer' started by Doghelmer, Feb 25, 2017.

  1. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    I've spotted a rare issue when playing my game in multiplayer mode: Basically, OnServerDisconnect gets called, but the client can still receive and send input as normal -- as if they weren't disconnected at all.

    No idea why this might be happening, but it seems like I might be able to work around it if, instead of immediately removing the client's avatar when OnServerDisconnect is called, I wait a few seconds and check again for an active connection. In this case, what would be the best method of checking to see that the connection was still active?

    I'm also curious about other methods of checking for disconnects. Oddly, the NetworkConnection variable "isConnected" does not seem to provide an accurate result in this instance.
     
  2. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    I have similar issues with my solution. I don't use the OnServerDisconnect event methods (or much of the HLAPI elements), but I do notice that the "disconnect" event (registered to the NetworkClient via NetworkClient.RegisterHandler) doesn't get fired when the server side initiates the disconnect. It does get fired though when the client side fails to connect and/or initiates a disconnect. Judging by your findings, it sounds like this might be a bug that exists within the HLAPI too..

    You've partly answered your question though. How I do it is just watch for the NetworkClient.isConnected going from true to false unexpectedly, for example in an Update loop, and treat it as an unexpected disconnect. A bit of a work-around, but it works fine for me.

    Hopefully this helps!
     
  3. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    @donnysobonny
    Are you doing this on the server side or the client side? If this is on the server side, how are you getting the NetworkClient? I'm able to get a list of NetworkConnections using NetworkServer.connections, but I'm not sure how to get the current NetworkClients (not sure if this is even something I'm supposed to do?) Using the NetworkConnection "isConnected" has been kind of flaky for me, and I was hoping NetworkClient's isConnected might be more accurate.
     
  4. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    Apologies, I assumed "NetworkClient" would give it away! I'm using the NetworkClient class on the client side, and the NetworkServerSimple class on the server side. So to answer your question, NetworkClient.isConnected is 100% reliable (in my testing) to determine an unexpected disconnect on the client side.

    NetworkConnection.isConnected will only be partially reliable on the client side, because there is only ever an active instance of the NetworkConnection class while you are connected. You can access the current instance via NetworkClient.connection, so in order to use that to determine whether there is an active connection you could just use a null check against NetworkClient.connection


    On the server side, I use the "disconnect" event (by registering an event handler to the NetworkServerSimple instance) and this works absolutely fine for me on the server side. So I assume your OnServerDisconnect should work fine on the server side.
     
  5. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    Ah, see it's more important that I determine whether the disconnect was real on the server side. My current flow is this:

    - OnServerDisconnect gets called on the server.
    - (server needs to determine whether the disconnect was real)
    - Server removes player's avatar from the game, does cleanup stuff.

    OnClientDisconnect doesn't happen at any point on the client, which is typically how I notify the client that they are done with the game -- so that's not an issue. The problem occurs exclusively on the server side.

    Right now, when OnServerDisconnect gets called, I'm actually waiting a split second and sending a TargetRPC to the client. If they send something back within a few seconds, it doesn't disconnect them. I'm not even sure if this works properly since the issue is so rare, but if you think there's a better method, let me know.
     
  6. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    Hmm yeah in that case it sounds like there's maybe an issue in the current process that you are using. You obviously have to allow time for a disconnect to happen (on both sides), especially when there's a lot of work for either side to carry out in order to clean things up, so this may be the root of your issue.

    When the issue happens, which side is actually initiating the disconnect? It's possible to both disconnect from the client side (closing your connection to the server) and from the server side (where the server closes the connection for a particular client). Also, do you get the same problem when you initiated the disconnect from the other side?
     
  7. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    The server side is initiating the disconnect with OnServerDisconnect. Not sure I follow -- you say "do you get the same problem when you initiated the disconnect from the other side". I'm not initiating anything myself, something or other is causing OnServerDisconnect to get called, which sets off this whole issue.. I think. I'm not sure if anything is getting called on the client side, as I haven't been able to reproduce the issue within the editor. What is the exact flow that you're using to catch this sort of disconnect?
     
  8. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    So, a disconnect is initiated via:
    • NetworkClient.Disconnect (to disconnect a client from the server, on the client side)
    • NetworkServer.DisconnectAll, NetworkServerSimple.Disconnect, NetworkServerSimple.DisconnectAllConnections (to disconnect all, or a specific client from the server, on the server side)
    • NetworkConnection.Disconnect (ultimately gets called by the above methods, to disconnect a single connection. If you manage connections yourself, you would use this to disconnect a client from the server, on the server side. Otherwise, ignore this!)
    If you're certain that you're not actually initiating the disconnect, then you'll want to investigate this further, because if OnServerDisconnect is being called unexpectedly, the client is being disconnected from the server for a potentially severe reason (of which there are many, but an example could be too many messages being sent over the network). Since you are using the NetworkManager, you should be able to debug problems by implementing the OnServerError and OnClientError methods. These will tell you about any potentially severe issues, and should hopefully give you more info on why the client is getting disconnected.

    So, the process is different on either side obviously, and I don't use the NetworkManager (I use registered handlers, but the idea should be the same):
    • On the server side, I find it to be almost 100% reliable to rely on the Disconnect registered event to detect and handle the disconnection of a client from the server (regardless of how the disconnection happened). This would be the equiv of NetworkManager.OnServerDisconnect
    • On the client side, a registered Disconnect event is only (currently) partially reliable. It gets called when connection fails and/or the client-side initiates the disconnect (via NetworkClient.Disconnect). However, if the server-side initiates the disconnect (via, in this case, NetworkConnect.Disconnect, on the client's connection), the Disconnect event doesn't seem to get fired. For you, this would be NetworkManager.OnClientDisconnect. So for this, I check for the change of the NetworkClient.isConnected changing from true to false to detect that the client has been disconnected from the server.

    Hopefully this helps, let me know if you're still stuck.
     
    Last edited: Mar 6, 2017
  9. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    OK, I think I understand a bit better now. Thanks for the help!