I have an application that opens a read-only TCP stream socket. I have set up KeepAlive to ensure that every second a message is sent to check if the connection is still ok. Wireshark shows that the KeepAlive messages are sent and also ACKd by the other computer. My application is running on windows.
The remote machine to where I open the socket is on a separate LAN adapter compared to the rest of the network/internet.
There are two scenarios that seem to react in a different way, and I would like to know why.
- I am connected to the internet. TCP Keep-Alive is going strong every second. I pull the LAN cable from the machine. The last TCP Keep-Alive is not ACKd and therefore
Socket.Connected
isfalse
, as expected. - I am not connected to the internet. TCP Keep-Alive is going strong every second. I pull the LAN cable from the machine. No TCP Keep-Alive package was sent to the remote machine at all, therefore
Socket.Connected
is stilltrue
.
Am I missing an important concept here on when a TCP Keep-Alive package is sent by the socket? For example, don't send if you don't have a network connection at all? And if so, how can I ensure that the socket is no longer Connected
?
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.SetupKeepAlive();
_socket.Blocking = false;
public static void SetupKeepAlive(this Socket socket, uint interval = 1000U)
{
if (socket is null)
{
throw new ArgumentNullException(nameof(socket));
}
// Get the size of the uint to use to back the byte array
var size = Marshal.SizeOf(0U);
// Create the byte array
var keepAlive = new byte[size * 3];
// Pack the byte array:
// Turn keep-alive on
Buffer.BlockCopy(BitConverter.GetBytes(1U), 0, keepAlive, 0, size);
// Set amount of time without activity before sending a keep-alive
Buffer.BlockCopy(BitConverter.GetBytes(interval), 0, keepAlive, size, size);
// Set keep-alive interval
Buffer.BlockCopy(BitConverter.GetBytes(interval), 0, keepAlive, size * 2, size);
// Set the keep-alive settings on the underlying Socket
_ = socket.IOControl(IOControlCode.KeepAliveValues, keepAlive, null);
}