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

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.

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;
}

Socket.Disconnect vs Socket.Close

What is the difference and which rules I must follow when working with socks?
I'm writing simple daemon, which must listen port and do some actions.
Socket.Close calls Dispose (but it's undocumented).
When using a connection-oriented Socket, always call the Shutdown method before closing the Socket. This ensures that all data is sent and received on the connected socket before it is closed. (msdn)
Your code should looks like this (at least I'd do it like this):
using (var socket = new Socket())
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
The Disconnect method takes a single parameter bool reuseSocket , according to msdn:
reuseSocket
Type: System.Boolean
true if this socket can be reused after the current connection is closed; otherwise, false.
which basically means, when you set reuseSocket to false it will be disposed after you close it.
The Shutdown method will not disconnect your socket, it will just disable sending/receiving data.

.Net Socket doesn't respond to remote disconnect?

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
}

How to abort socket's BeginReceive()?

Naturally, BeginReceive() will never end if there's no data.
MSDN suggests that calling Close() would abort BeginReceive().
However, calling Close() on the socket also performs a Dispose() on it, as figured out in this great answer, and consequently EndReceive() would throw an exception because the object is already disposed (and it does!).
How should I proceed?
It seems like this is by (the very dumb) design. You must have this exception thrown and caught in your code.
MSDN looks silent about it indeed, but if you look at the documentation of another asynchronous socket method, BeginConnect(), here's what we find:
To cancel a pending call to the
BeginConnect() method, close the
Socket. When the Close() method is
called while an asynchronous operation
is in progress, the callback provided
to the BeginConnect() method is
called. A subsequent call to the
EndConnect(IAsyncResult) method will
throw an ObjectDisposedException to
indicate that the operation has been
cancelled.
If it is the proper way of doing for BeginConnect, it is probably so for BeginReceive as well. This is certainly a poor design on the part of Microsoft's async API, because making the user necessarily throw and catch exception as a part of a normal flow would annoy the debugger. You have really no way to "wait" until the operation is completed, because Close() is what completes it in the first place.
I am surprised no one recommended using SocketOptions.
Once the stack has the send or receive operation it is bound by the socket options of the socket.
Use a small send or receive timeout and use it before the operation so you don't care if it's changed during that same operation to something shorter or longer.
This will cause more context switching but will not require closing the socket under any protocol.
For example:
1) Set a small timeout
2) Perform operations
3) Set timeout larger
This is similar to using Blocking = false but with an automatic timeout that you specify.
You can read my solution of this problem here(using comment of Pavel Radzivilovsky here):
UdpClient.ReceiveAsync correct early termination
For TCP socket connections, you can use the Connected property to determine the state of the socket before trying to access any disposed methods. Per MSDN:
"The Connected property gets the connection state of the Socket as of the last I/O operation. When it returns false, the Socket was either never connected, or is no longer connected."
Since it says "no longer connected" it implies that a Close() was previously called on the socket. If you check whether the socket is Connected at the start of the receive callback, there will be no exception.
In the ReceiveCallback I checked client.Connected within the try block.
Now, when data is received after BeginReceive, I can call client.Close();
This way, I do not see exceptions. I send modbus-TCP requests every 200mS, and get responses in time. The console output looks clean. I used a windows forms app, to test this.
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
if (client.Connected)
{
// Read data from the remote device.
state.dataSize = client.EndReceive(ar);
if (state.dataSize > 0)
{
Console.WriteLine("Received: " + state.dataSize.ToString() + " bytes from server");
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, state.dataSize));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AsyncCallback(ReceiveCallback), state);
state.dataSizeReceived = true; //received data size?
dataSize = state.dataSize;
buffer = state.buffer.ToArray();
dataSizeReceived = state.dataSizeReceived;
string hex = ByteArrayToString(state.buffer, state.dataSize);
Console.WriteLine("<- " + hex);
receiveDone.Set();
client.Close();
}
else
{
Console.WriteLine("All the data has arrived");
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
Console.WriteLine("Length: " + state.sb.Length.ToString());
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Another solution would be to send "yourself" a "control message" using a socket bound to a different port. It's not exactly an abort, but it would end your async operation.
I was struggling with this as well but as far as I can tell using a simple boolean flag before calling .BeginReceive() will work as well (so there'll be no need for exception handling). Since I already had start/stop handling, this fix was a matter of one if statement (scroll down to the bottom of the OnReceive() method).
if (_running)
{
_mainSocket.BeginReceive(_data, 0, _data.Length, SocketFlags.None, OnReceive, null);
}
Should I have overlooked something with this approach, let me know!

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