I have trouble with detecting client disconnect from host. Currently my code looks like this:
Task.Run(() => {
// Create server
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) {
ReceiveTimeout = -1,
};
server.Bind(new IPEndPoint(IPAddress.Any, port));
server.Listen(-1);
// Start listening
while (true) {
Socket socket = server.Accept();
new Thread(() => {
try {
Process(socket);
} catch (Exception ex) {
Trace.WriteLine("Socket connection processing error: " + ex.Message);
}
}).Start();
}
});
// Host client process
void Process(Socket socket) {
byte[] response;
int received;
var ip = IPAddress.Parse(((IPEndPoint) socket.RemoteEndPoint).Address.ToString());
Events.OnNodeConnected(ip);
while (true) {
// Rceive data
response = new byte[socket.ReceiveBufferSize];
received = socket.Receive(response);
// Check connection
if (!socket.IsConnected()) {
socket.Close();
Events.OnNodeDisconnected(ip);
return;
}
try {
// Decode recieved data
List < byte > respBytesList = new List < byte > (response);
And the IsConnected() extension:
public static class SocketExtensions {
public static bool IsConnected(this Socket socket) {
try {
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
} catch (SocketException) {
return false;
}
}
}
Works when I close the application, but not when I turn off the network card. I'm testing this on Debian virtual machines running on VirtualBox. Is there any way to detect disconnection in this case?
Works when I close the application, but not when I turn off the network card.
Turning off the network card is actually not a disconnect. If the network card is turned on again the existing connection can continue (providing the interface has still the same IP address) - this is not unusual for example when suspending a laptop and resuming it later.
With TCP a real disconnect is only an explicit disconnect (FIN gets send) which is done when explicitly closing the socket or which gets implicitly done by the OS kernel on application exit or when the application crashes.
What you instead ask for is not an explicit disconnect but to detect if the peer is currently not reachable, like when the line is (temporarily) disconnected or the system has crashed. This can be done by having some kind of heartbeat either at the application level or at the TCP level. The latter is called TCP keep alive and works by sending empty TCP packets and check if an ACK is sent back. See here for an example on how to use this.