Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TcpClient/NetworkStream not detecting disconnection

I created a simple persistent socket connection for our game using TcpClient and NetworkStream. There's no problem connecting, sending messages, and disconnecting normally (quitting app/server shuts down/etc).

However, I'm having some problems where, in certain cases, the client isn't detecting a disconnection from the server. The easiest way I have of testing this is to pull out the network cable on the wifi box, or set the phone to airplane mode, but it's happened in the middle of a game on what should otherwise be a stable wifi.

Going through the docs for NetworkStream etc, it says that the only way to detect a disconnection is to try to write to the socket. Fair enough, except, when I try, the write passes as if nothing is wrong. I can write multiple messages like this, and everything seems fine. It's only when I plug the cable back in that it sees that it's disconnected (all messages are buffered?).

The TcpClient is set to NoDelay, and there's a Flush() called after every write anyway.

What I've tried:

  • Writing a message to the NetworkStream - no joy
  • CanWrite, Connected, etc all return true
  • TcpClient.Client.Poll( 1000, SelectMode.SelectWrite ); - returns true
  • TcpClient.Client.Poll( 1000, SelectMode.SelectRead ) && TcpClient.Client.Available == 0 - returns true
  • TcpClient.Client.Receive(buffer, SocketFlags.Peek) == 0 - when connected, blocks for about 10-20s, then returns true. When no server, blocks forever(?)
  • NetworkStream.Write() - doesn't throw an error
  • NetworkStream.BeginWrite() - doesn't throw an error (not even when calling EndWrite())
  • Setting a WriteTimeout - had no effect
  • Having a specific time where we haven't received a message from the server (normally there's a keep-alive) - I had this, but removed it, as we were getting a lot of false-positives due to lag etc (some clients would see between 10-20s of lag)

So am I doing something wrong here? Is there any way to get the NetworkStream to throw an error (like it should) when writing to a socket that should be disconnected?

I've no problem with a keep-alive (the default case is the server will notify the client that it hasn't received anything in a while, and the client will send a heartbeat), but at the minute, according to the NetworkStream everything's hunky-dory.

It's for a game, so ideally the detection should be quick enough (as the user can still move through the game until they need to make a server call, some of which will block the UI, so the game seems broken).

I'm using Unity, so it's .Net 2.0

like image 652
divillysausages Avatar asked Jul 09 '15 16:07

divillysausages


1 Answers

is to pull out the network cable on the wifi box

That's a good test. If you do that the remote party is not notified. How could it possibly find out? It can't.

when I try, the write passes as if nothing is wrong

Writes can (and are) buffered. They eventually enter a block hole... No reply comes back. The only way to detect this is a timeout.

So am I doing something wrong here?

You have tried a lot of things but fundamentally you cannot find out about disconnects if no reply comes back telling you that. Use a timeout.

like image 123
usr Avatar answered Oct 07 '22 19:10

usr