.Net Socket doesn't respond to remote disconnect? - c#

I'm writing a small (C#) client application that sends data using a TCP/IP connection to a remote server. I'm using the standard .Net TcpClient object and want to leave the connection open from the client end as I am regularly submitting data packets to the server. However, it is possible that the server may close the connection, in which case I need to know to re-connect before sending my next packet.
Using Wireshark, I can see (only) the following dialogue when the server terminates the connection:
server >>> FIN, ACK ACK <<< client
What I do not see is my client responding with a FIN of its own, to complete the connection shutdown. The result is that my client program only finds out that the connection is down after sending the next data packet.
Is there any way I can set up TcpClient or its underlying Socket so as to complete the disconnect, and provide some feedback so that my client code knows to re-connect before sending the next packet?
Added in response to comment below:
My sending code is very simple - the object that maintains the TcpClient and NetworkStream member variables, has a member function containing (essentially) the following:
bool sent = false;
byte[] buffer = Encoding.UTF8.GetBytes(dataString);
while (!sent)
{
try
{
m_outStream.Write(buffer, 0, buffer.Length);
sent = true;
}
catch (Exception ex)
{
if (m_outStream != null) { m_outStream.Dispose(); }
m_client = new TcpClient(AddressFamily.InterNetwork);
m_client.Connect(ipAddress, ipPort);
m_outStream = m_client.GetStream();
}
}
With m_client and m_outStream initialized, this simply performs a single pass every time. Then using Wireshark I can see the server send a packet with flags FIN, ACK to which the client responds with ACK.
The next time I call my function, the data is sent out with PSH, ACK, and the server responds with RST, ACK but does not read the incoming data. No exception is raised by the client.
Then I call my function a second time, and an exception is raised causing the connection to be re-started.

In general you should be able to use the Connected property on the TcpCient instance:
See here:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.connected.aspx
However:
Because the Connected property only reflects the state of the
connection as of the most recent operation, you should attempt to send
or receive a message to determine the current state. After the message
send fails, this property no longer returns true. Note that this
behavior is by design. You cannot reliably test the state of the
connection because, in the time between the test and a send/receive,
the connection could have been lost. Your code should assume the
socket is connected, and gracefully handle failed transmissions.
Try the following to make sure the Connected flag holds the most recent state:
var tcpClient = new TcpClient ();
tcpClient.Connect();
var stream = tcpClient.GetStream();
// buffer size need to be > 0
int[] buffer = new int[1];
stream.Read(buffer, 0, 0);
if(!tcpClient.Connected)
// do something
Based on decompilation it should be possible to read 0 bytes from a stream, at least there is no check in the .NET Framework TcpClient that prevents this. However it might not be aloud in the external code that is called from the framework to actually read from the network stream.
Be sure to Dispose of both the TcpClient and the Stream after your done, disposing the TcpClientdoes not dispose of the Stream so you need todo this manually, afterwards all resources are freed up (after GC).

From MSDN TcpClient.Connected property:
Type: System.Boolean
true if the Client socket was connected to a remote resource as of the most recent operation; otherwise, false.
This means, you would have to send some data to the server to detect the broken connection. Reading does not work, as you read from the buffer.
See my answer on a related question (https://stackoverflow.com/a/25680975/2505186),
linking the answer of someone else, where a suitable way is described to detect the connection status:
How to check if TcpClient Connection is closed?
Important for you:
The client does not close the connection automatically, when the server does so. The connection is in CLOSE_WAIT state then at the client side and in FIN_WAIT2 state at the server side. See the related section in the wikipedia article Transmission Control Protocol. Using the code from the linked answer above, you can detect that the connection is about to get closed. Further, you can finish the closing procedure then and reopen it if needed.

The method I use for detecting connected status is this one.
static class SocketExtensions
{
/// <summary>
/// Extension method to tell if the Socket REALLY is closed
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
}
When I want to shutdown the connection, I call the following. Closing the underlying stream, and then the client object on top.
I enclose it in trys and catches to ensure that an attempt at closing them is attempted on each.
Note: PeerStream in this case is the NetworkStream (from Client.GetStream())
/// <summary>
/// Method will disconnect this peer forcefully
/// </summary>
public void Disconnect()
{
try
{
PeerStream.Close();
}
catch (Exception ee)
{
}
try
{
_client.Client.Disconnect(false);
}
catch (Exception ee)
{
}
}

I have found a partial answer to my question that solves the immediate problem.
While I still don't know if I can get my TcpClient to complete the disconnection, I can reliably discover whether the socket has disconnected using the following code:
if (m_client.Client.Poll(1000, SelectMode.SelectRead)
&& (m_client.Client.Available == 0))
{
// Connection has gone - reconnect!
m_client = new TcpClient(AddressFamily.InterNetwork);
m_client.Connect(ipAddress, ipPort);
}
else
{
// Connection is good, nothing to do
}

Related

Determine broken connection in TCP server

I wrote a tcp server, each time a client connection accepted, the socket instance returned by Accept or EndAccept which is called handler and many other information gathered in object called TcpClientConnection, I need to determine whether a connection is connected or not at some specific interval times, the Socket.Connected property is not reliable and according to the documentation i should use the Poll method with SelectRead option to do it.
with a test scenario i unplug the client cable, and wait for broken alarm which is built upon the handler.Poll(1, SelectMode.SelectRead), it should return true but never it happened.
This is a fundamentally caused by the way the TCP and IP protocols work. The only way to detect if a connection is disconnected is to send some data over the connection. The underlying TCP protocol will cause acknowledgements to be sent from the receiver back to the sender thereby allowing a broken connection to be detected.
These articles provide some more information
Do I need to heartbeat to keep a TCP connection open?
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
According to the documentation of Socket.Poll:
This method cannot detect certain kinds of connection problems, such as a broken network cable, or that the remote host was shut down ungracefully. You must attempt to send or receive data to detect these kinds of errors.
In another words - Poll is useful for checking if some data arrived and are available to your local OS networking stack.
If you'd need to detect the connection issues you need to call blocking read (e.g. Socket.Receive)
You can also build a simple initialization miniprotocol to exchange some agreed 'hello' back and forth message.
Here is a simplified example how you can do it:
private bool VerifyConnection(Socket socket)
{
byte[] b = new byte[1];
try
{
if (socket.Receive(b, 0, 1, SocketFlags.None) == 0)
throw new SocketException(System.Convert.ToInt32(SocketError.ConnectionReset));
socket.NoDelay = true;
socket.Send(new byte[1] { SocketHelper.HelloByte });
socket.NoDelay = false;
}
catch (Exception e)
{
this._logger.LogException(LogLevel.Fatal, e, "Attempt to connect (from: [{0}]), but encountered error during reading initialization message", socket.RemoteEndPoint);
socket.TryCloseSocket(this._logger);
return false;
}
if (b[0] != SocketHelper.HelloByte)
{
this._logger.Log(LogLevel.Fatal,
"Attempt to connect (from: [{0}]), but incorrect initialization byte sent: [{1}], Ignoring the attempt",
socket.RemoteEndPoint, b[0]);
socket.TryCloseSocket(this._logger);
return false;
}
return true;
}

C# Sockets: accept a socket, ignore its message, send one back

We have a C# server that receives TCP messages using sockets. The normal flow is to call socket.Accept(), use socket.BeginReceive() and socket.EndReceive() to receive the message, then use socket.Send() to send a response. This works fine.
When too many requests come in at once, however, we want to reject the overflow immediately, so we don't overwhelm the server. It's easy enough to close the socket directly after Accept(); but that doesn't allow us to send a meaningful "too busy" message back to the client.
What I'd like to do is simply call Accept(), then call Send(), without receiving the incoming message. I have tried this, and the server claims to send my data, but my client receives nothing but an empty response. I have tried using both the synchronous Send() and the asynchronous BeginSend()/EndSend(), but neither gets the message back to the client.
Is it possible to send a message on an accepted socket without first receiving the incoming message? If so, is there a piece I'm missing to make it work?
Here's a code snippet showing what I'm trying to do:
while (!_Done)
{
Socket socket = null;
try
{
socket = _ListeningSocket.Accept();
}
catch (Exception) { }
if (socket != null)
{
if (TooBusy())
{
// My new code
byte[] send = GetTooBusyResponse();
int ret = socket.Send(send);
Console.WriteLine("socket.Send() returned " + ret);
socket.Close();
socket = null;
}
else
{
// Existing, working code (using custom objects)
ClientConnection connection = new ClientConnection(this, socket, !_RequireAuthentication);
lock (_ConnectionsToken)
_Connections.Add(connection);
connection.BeginReceive();
}
}
}
According to MSDN,
The Close method closes the remote host connection and releases all
managed and unmanaged resources associated with the Socket. Upon
closing, the Connected property is set to false.
For connection-oriented protocols, it is recommended that you call
Shutdown before calling the Close method. This ensures that all data
is sent and received on the connected socket before it is closed.
If you need to call Close without first calling Shutdown, you can
ensure that data queued for outgoing transmission will be sent by
setting the DontLinger Socket option to false and specifying a
non-zero time-out interval. Close will then block until this data is
sent or until the specified time-out expires. If you set DontLinger to
false and specify a zero time-out interval, Close releases the
connection and automatically discards outgoing queued data.
So either call Shutdown first, or set the DontLinger option to false and set a non-zero timeout.

TCP Communication-Asynchronous Read Loop doesn't end

I am using Asynchronous TCP server/client communication. I have noticed in my log that the same client reconnects several times. However, it never shows that it was disconnected. My code has logging for both connection and disconnection. So why does readAsync stay in loop while the client has disconnected? Here is the code for your reference:
private async Task Accept(TcpClient client)
{
//get client information
string clientEndPoint = GetClientIPAddress(client);
log.Info("Client connected at " + clientEndPoint); //same client is connected several times in log
await Task.Yield ();
try
{
using (client)
using (NetworkStream stream = client.GetStream ())
{
byte[] dataReceived = new byte [100];
while (await stream.ReadAsync(dataReceived, 0, dataReceived.Length) != 0) //read input stream - 0=>end of stream is reached
{
//pass on data for processing
var task = ProcessData(dataReceived);
}
}
log.Info("Closing client connection " + clientEndPoint);//this line is never reached in log
if (client.Connected)
client.Close();
} //end try
catch (Exception ex)
{
log.Error(ex.Message);
log.Info("Closing client connection " + clientEndPoint);
if (client.Connected)
client.Close();
}
It looks like you may have a half-open problem. You should periodically write data to determine whether the socket is still connected; reads can detect graceful shutdowns but not half-open scenarios.
I describe the half-open problem more on my blog.
Did you check if TCP keep alive is set? That should detect if connection is broken.
Also, check if you got zero length bytes on receive, this means that connection is closed.
Edit: Keep Alive is standard method to check if connection is active, this means that one side sends small chunks of data to the other side periodically: http://en.wikipedia.org/wiki/Keepalive.
Many components have this feature already implemented. I've never used TcpClient class, but it must be some wrapper class for Socket over TCP and, as doc states, this class have exposed underlaying Socket (you can use Socket class for TCP also, but never mind). And this Socket have method SetSocketOption. So try:
client.Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);

Detect closed network connection

I've written a number of small programs that communicate via TCP. I'm having endless issues with the system hanging because one program has closed its network connection, and the other end-point somehow fails to notice that it's now disconnected.
I was expecting doing I/O on a TCP connection that has been closed to throw some kind of I/O exception, but instead the program seems to just hang, waiting forever for the other end-point to reply. Obviously if the connection is closed, that reply is never coming. (It doesn't even seem to time out if you leave it for, say, twenty minutes.)
Is there some way I can force the remote end to "see" that I've closed the network connection?
Update: Here is some code...
public sealed class Client
{
public void Connect(IPAddress target)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ipAddress, 1177);
_stream = new NetworkStream(socket);
}
public void Disconnect()
{
_stream.Close();
}
}
public sealed class Server
{
public void Listen()
{
var listener = new TcpListener(IPAddress.Any, 1177);
listener.Start();
var socket = listener.AcceptSocket();
_stream = new NetworkStream(socket);
...
}
public void Disconnect()
{
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(false);
}
}
When an application closes a socket the right way, it sends a message containing 0 bytes. In some cases you may get a SocketException indicating something went wrong. In a third situation, the remote party is no longer connected (for instance by unplugging the network cable) without any communication between the two parties.
If that last thing happens, you'll have to write data to the socket in order to detect that you can no longer reach the remote party. This is why keep-alive mechanisms were invented - they check every so often whether they can still communicate with the other side.
Seeing the code you posted now: when using NetworkStream the Read operation on it would return a value of 0 (bytes) to indicate that the client has closed the connection.
The documentation is mentions both
"If no data is available for reading, the Read method returns 0."
and
"If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes."
in the same paragraph. In reality NetworkStream blocks if no data is available for reading while the connection is open.
Hi MathematicalOrchid,
You might find what you are looking for here:
http://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html
There is some great information there when it comes to working with TCP sockets and detecting half open connections.
You can also refer to this post which seems to have the same solution:
TcpClient communication with server to keep alive connection in c#?
-Dave
You are opening the socket, and assigning it to the stream. At the end of the process, you close the network stream, but not the socket.
For NetworkStream.Close() to close the underlying socket it must have the ownership parameters set to true in the constructor - See MSDN Docs at http://msdn.microsoft.com/en-us/library/te7e60bx.aspx.
This may result in the connection hanging as the underlying socket was not correctly closed.
Change
_stream = new NetworkStream(socket);
To
_stream = new NetworkStream(socket, true);
On a side note, if you do not require a maximum performance for your small app you should try using TCPClient instead - http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=vs.100%29.aspx. This is a wrapper around socket and it provides connection state checking facilities.

Socket closing automatically

Is there a reason why a Socket should close by itself, after 2h? I am receiving data every second from this socket, and writing back some tiny "keep-alive" data every 30s.
Before sending, I check if socket is still connected using the following method:
public bool IsSocketReadyForWriting(Socket s)
{
try
{
if (!s.Connected)
{
Log.Info("Socket.Connected was false");
return false;
}
// following line will throw if socket disconnected
bool poll = s.Poll(2000, SelectMode.SelectWrite);
if (!poll)
{
try
{
// if poll is false, socket is closed
Log.Info("poll is false");
this.Close();
}
catch { }
return false;
}
Log.Debug("still connected");
return true;
}
catch (Exception ex)
{
Log.Error("Error while checking if socket connected", ex);
return false;
}
}
Everything works fine for about 2h, then suddenly Socket.Poll returns false, and the Socket gets closed.
Is there a setting which controls this, or am I doing something really wrong?
[Edit]
Forgot to mention: I control both server and client side of the link. These are both C# apps, one of them creates a listening socket, the other one opens a connection and sends data. They communicate without problems for 2h (no memory leaks and stuff), then the socket closes.
When this happens, I can reconnect the socket again easily, but I am just wandering if anyone knows why could be the reason for this.
By default a TCP socket is writable when there's at least one byte of space available in the socket send buffer. To reverse that - the socket is not writable when there's enough unacknowledged data sitting in the "output queue".
That said, pull out wireshark or whatever Microsoft provides for packet sniffing and see what's going on on the wire. Are your heartbeat chunks getting ACK-ed? Does the receiver window stay open or does it go to zero? Or are you just getting explicit RST or a FIN from some intermediate switch?
One way to mitigate temporary clogged pipe is to increase the send buffer size, which is kind of tiny by default on Windows - 8192 iirc. See the setsockopt (.NET probably has a version of that) and the SO_SNDBUF option.
Could be the server that is closing the connection? Do you have control over it?

Categories