C# socket blocking with zero data - c#

I have implemented C# tcp-ip client (both synchronous & async reading socket).
After each SocketException, I'm automatically reconnecting connection with server.
Then I have tested communication of client with ncat in windows. Here, if I kill ncat, it throws SocketException in C# client and everything works as I imagine.
But then I have tested it with ncat in linux - here communication works OK, but if I kill ncat server (the same settings like at Windows - ncat -l -k -p xxxx), huge amount of empty data (zero B) is received in callback (or waiting on socket in sync version) and no exception is thrown.
One thing is that Windows / Unix version of ncat can have different behavior. But still I need to solve this weird behavior for any version of tcp-ip server.
/* ------------------------------------------------------------------------- */
public void WaitForData()
{
try
{
if (callback == null)
callback = new AsyncCallback(OnDataReceived);
SocketPacket packet = new SocketPacket();
packet.thisSocket = socket;
m_result = socket.BeginReceive
(packet.dataBuffer, 0, 256,
SocketFlags.None, callback, packet);
}
catch (SocketException ex) { ///reconnecting }
}
/* ------------------------------------------------------------------------- */
public class SocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[256];
}
/* ------------------------------------------------------------------------- */
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
int iRx = theSockId.thisSocket.EndReceive(asyn);
char[] chars = new char[iRx];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
string szData = new string(chars);
szData = szData.Replace("\n", String.Empty);
processMessage(szData);
WaitForData();
}
catch (ObjectDisposedException) { }
catch (SocketException ex) { ///reconnecting }
}
Thank you!

Solved
In OnDataReceived callback, I check amount of incoming data, so I do:
if (iRx == 0)
throw new SocketException(Convert.ToInt16(SocketError.HostDown));

TCP receiver can never get the exact status of the remote connection. Killing the process will send FIN (receive is zero) or RST(get exception) depending on the TCP/IP stack implementation. There are other condition where the application are completely unaware of the connection breakage. Suppose if the remote system is forcefully reset or the cable wire is unplugged or the IP address is changed, there is no way you can get to know the connection broken until you send some data. If your application need to know the status of the connection, it can send some dummy data every 1 minute to make sure the connection alive.

Related

Why isn't TcpListener listening?

We have a C++ v100 application that is processing every event in our system, listening on port 1705, running off the Hostname. (it works perfectly for the C++ app, and we don't want to change anything in the c++ code) We are trying to intercept some of those events into a C# 4.5.2 solution, simply to display specific events in our new web system.
I have coded the following, in an attempt to listen to port 1705 traffic... but I never receive any data. (I can create events that get sent to 1705)
The following code runs, and it makes it to 'Waiting for a connection', but never makes it to 'Connected!'. If you see any reason in the following code as to why I wouldn't be receiving data, please let me know:
private void PortListener()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
var port = 1705;
var localAddr = IPAddress.Parse(Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
var bytes = new byte[256];
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
var client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
var stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
var data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
//TODO: Process the data
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server?.Stop();
}
}
Make sure that you are binding/listening to the right ip-address. If you bind/listen on localhost (127.0.0.1) you can only connect from the same host.
Check what
Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
really produces.
I'm doing this all wrong. In order to listen to an already opened Port, I need to use a TcpClient to connect and listen. Only a single TcpListener is allowed per port. Several TcpClients can connect at once. Sigh.

Why does my C# TcpClient fail to receive content from the server if the server sends before reading everything from the client?

In an application I'm working on I want to disconnect clients that are trying to send me packets that are too large.
Just before disconnecting them I want to send them a message informing them about the reason for disconnecting them.
The issue I am running into is that the client cannot receive this server message, if the server does not read everything the client has send him first. I do not understand why this is happening.
I've managed to narrow it down to a very small test setup where the problem is demonstrated.
The StreamUtil class is a simple wrapper class that helps to get around the TCP message boundary problem, basically on the sender side it sends the size of each message first and then the message itself, and on the receiver side it receives the size of the message first and then the message.
The client uses a ReadKey command to simulate some time between sending and receiving, seeing in my real application these two actions are not immediately back to back either.
Here is a test case that works:
Run server as shown below
Run client as shown below, it will show a "Press key message", WAIT do not press key yet
Turn off server since everything is already in the clients receive buffer anyway (I validated this using packet sniffer)
Press key on the client -> client correctly shows the messages from the server.
This is what I was expecting, so great so far no problem yet.
Now in the server code, comment out the 2nd receive call and repeat the steps above.
Step 1 and 2 complete successfully, no errors sending from client to server.
On step 3 however the client crashes on the read from the server, EVEN though the server reply HAS arrived on the client (again validated with packet sniffer).
If I do a partial shutdown (eg socket.Shutdown (...send...)) without closing the socket on the server, everything works.
1: I just cannot get my head around WHY not processing the line of text from the client on the server causes the client to fail on receiving the text send back from the server.
2: If I send content from server to client but STOP the server before actually closing the socket, this content never arrives, but the bytes have already been transmitted to the server side... (see ReadKey in server to simulate, basically I block there and then just quit the server)
If anyone could shed light on these two issues, I'd deeply appreciate it.
Client:
class TcpClientDemo
{
public static void Main (string[] args)
{
Console.WriteLine ("Starting....");
TcpClient client = new TcpClient();
try
{
client.Connect("localhost", 56789);
NetworkStream stream = client.GetStream();
StreamUtil.SendString(stream, "Client teststring...");
Console.WriteLine("Press key to initiate receive...");
Console.ReadKey();
Console.WriteLine("server reply:" + StreamUtil.ReceiveString(stream));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
client.Close();
}
Console.WriteLine("Client ended");
Console.ReadKey(true);
}
}
Server:
class TcpServerDemo
{
public static void Main (string[] args)
{
TcpListener listener = new TcpListener (IPAddress.Any, 56789);
listener.Start ();
Console.WriteLine ("Waiting for clients to serve...");
while (true)
{
TcpClient client = null;
NetworkStream stream = null;
try
{
client = listener.AcceptTcpClient();
stream = client.GetStream();
//question 1: Why does commenting this line prevent the client from receiving the server reply??
Console.WriteLine("client string:" + StreamUtil.ReceiveString(stream));
StreamUtil.SendString(stream, "...Server reply goes here...");
//question 2: If I close the server program without actually calling client.Close (while on this line), the client program crashes as well, why?
//Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
break;
}
finally
{
if (stream != null) stream.Close();
if (client != null) client.Close();
Console.WriteLine("Done serving this client, everything closed.");
}
}
listener.Stop();
Console.WriteLine("Server ended.");
Console.ReadKey(true);
}
}
StreamUtil:
public class StreamUtil
{
public static byte[] ReadBytes (NetworkStream pStream, int byteCount) {
byte[] bytes = new byte[byteCount];
int bytesRead = 0;
int totalBytesRead = 0;
try {
while (
totalBytesRead != byteCount &&
(bytesRead = pStream.Read (bytes, totalBytesRead, byteCount - totalBytesRead)) > 0
) {
totalBytesRead += bytesRead;
Console.WriteLine("Read/Total:" + bytesRead + "/" + totalBytesRead);
}
} catch (Exception e) {
Console.WriteLine(e.Message);
}
return (totalBytesRead == byteCount) ? bytes : null;
}
public static void SendString (NetworkStream pStream, string pMessage) {
byte[] sendPacket = Encoding.ASCII.GetBytes (pMessage);
pStream.Write (BitConverter.GetBytes (sendPacket.Length), 0, 4);
pStream.Write (sendPacket, 0, sendPacket.Length);
}
public static string ReceiveString (NetworkStream pStream) {
int byteCountToRead = BitConverter.ToInt32(ReadBytes (pStream, 4), 0);
Console.WriteLine("Byte count to read:"+byteCountToRead);
byte[] receivePacket = ReadBytes (pStream, byteCountToRead);
return Encoding.ASCII.GetString (receivePacket);
}
}
The client fails because it detects the socket was already closed.
If C# socket operations detect a closed connection during earlier operations, an exception is thrown on the next operation which can mask data which would otherwise have been received
The StreamUtil class does a couple of things when the connection is closed before/during a read:
Exceptions from the reads are swallowed
A read of zero bytes isn't treated
These obfuscate what's happening when an unexpected close hits the client.
Changing ReadBytes not to swallow exceptions and to throw a mock socket-closed exception (e.g. if (bytesRead == 0) throw new SocketException(10053);) when it reads zero bytes I think makes the outcome more clear.
Edit
I missed something subtle in your examples - your first example causes a TCP RST flag to be sent as soon as the server closes connection, due to the socket being closed with data waiting to be read.
The RST flag results in a closedown that doesn't preserve pending data.
This blog has some discussion based on a very similar scenario (web server sending a HTTP error).
So I don't think there's an easy fix, options are:
As you already tried, shutdown the socket on the server before closing to force a FIN to be sent before the RST
Read the data in question but never process it (taking up bandwidth for no reason)

Reset TCP connection if server closes/crashes mid connection

I have a tcp connection like follows:
public void ConnectToServer()
{
string mac = GetUID();
while(true)
{
try
{
tcpClient = new TcpClient("xx.x.xx.xxx", xxxx);
networkstream = new SslStream(tcpClient.GetStream());
networkstream.AuthenticateAsClient("xx.x.xx.xxx");
networkstream.Write(Encoding.UTF8.GetBytes("0002:" + mac + "\r\n"));
networkstream.Flush();
string serverMessage = ReadMessage(networkstream);
Console.WriteLine("MESSAGE FROM SERVER: " + serverMessage);
}
catch (Exception e)
{
tcpClient.GetStream().Close();
tcpClient.Close();
}
}
}
This works fine and can send a receive data to/from the server.
What I need help with, if the server isn't running when the client starts, it'll wait and then connect once the server is up. But, if both the client and server are running and everything is working, if I close the server, the client will not reconnect(because I don't have anything to handle the event yet).
I have seen some answers on here that suggest polling and such. Is that the only way? The ReadMessage method that I call get into an infinite loop as well. I can post that code if need be.
I would really like to detect when the server closes/crashes and close the stream and the tcpclient and reconnect ASAP.
Here is my readmessage:
static string ReadMessage(SslStream sslStream)
{
if (sslStream.CanRead)
{
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
string message_type = null;
string actual_message = null;
do
{
try
{
Console.WriteLine("LENGTH: " + buffer.Length);
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
message_type = messageData.ToString().Substring(0, 5);
actual_message = messageData.ToString().Substring(5);
if (message_type.Equals("0001:"))
{
m_Window pop = new m_Window();
pop.callHttpPost(null, new EventArgs());
}
if (messageData.ToString().IndexOf("\r\n") != -1)
{
break;
}
}
catch (Exception e)
{
Console.WriteLine("ERROR: " + e.Message);
}
} while (bytes != 0);
return messageData.ToString();
}
return("CONNECTION HAS BEEN LOST");
}
With TCP you have 2 kinds of a server disconnect:
the server is closed
the server crashes
When the server is closed, you are going to receive 0 bytes on your client socket, this is the way you know that the peer has closed its end of the socket, which is called a half close.
But thing get more ugly if the server crashes.
When that happens again you have several possibilities.
If you don't send anything from the client to the server, the you have not way to find out that the server has indeed crashed.
The only way to find out that the server crashed is by letting the client send something or by activating keep alive. If you send something to a server socket that does not exist, you will have to wait a rather long period, because TCP is going to try several times, with retransmits untill there is a server response. When TCP has retried several times, then it will finally bail out and if you have a blocking socket you will see that the send failed, which means you should close your socket.
Actually there is a third possible server disconnect, that is a reset, but this is exceptionally used. I assume here that if there is a gracefull server shutdown, a normal close on the socket on the server end is executed. Which will end up in a FIN being sent instead of a RST, which is the exceptional case.
Now back to your situation, if the server crashes, it is inherently in the design of TCP, because of all those retransmission timeouts and increasing delays, that you will have to wait some time to actually detect that there is a problem. If the server is gracefully closed and startup again, this is not the case, this you detect immediately by receiving 0 bytes.

How to detect a disconnected socket C#?

I've been working on a socket client program in C# and am wondering how to detect when the other end of a socket has disconnected itself "ungracefully" as in a network cable being unplugged or a hard reset.
I have these functions below to access the socket and according to the SO question here and this MSDN article, the best way to check for a disconnected socket is to send a 1-byte message with a length of 0. If an exception is thrown and WSAEWOULDBLOCK is not the error code then the socket is disconnected. I have tried this but after hard reseting the server connection the client will call Send(new byte[1], 0, 0, SocketFlags.None) and return successfully and the Receive() command right afterwards returns the WSAEWOULDBLOCK error.
What gives??
Here's my code below. _socket is set to non-blocking mode:
private int nonBlockRecv(byte[] recvBytes, int offset, int size, SocketFlags sf)
{
int bytesRecv = 0;
while (true)
{
try
{
nonBlockSend(new byte[1], 0, 0, sf);
bytesRecv = _socket.Receive(recvBytes, offset, size, sf);
break;
}
catch (SocketException excp)
{
if (excp.ErrorCode != 10035) // WSAEWOULDBLOCK
throw excp;
}
}
return bytesRecv;
}
private int nonBlockSend(byte[] sendBytes, int offset, int size, SocketFlags sf)
{
int bytesSent = 0;
while (true)
{
try
{
_socket.Send(sendBytes, offset, size, sf);
break;
}
catch (SocketException excp)
{
if (excp.ErrorCode != 10035) // WSAEWOULDBLOCK
throw excp;
}
}
return bytesSent;
}
Edit: This may be beneficial but the server is Windows Mobile device. I read in another thread that different OSs maybe able to send socket close signals when they're dying. Perhaps the Windows Mobile OS does not do this??
If the remote computer gracefully disconnects the session, the
Socket.Receive() method will return with 0 bytes. You must detect that
to know that the remote end has disconnected:
int recv = sock.Receive(data);
if (recv == 0)
{
// Remote client has disconnected.
}
else
{
// Remote client has sent data.
}
Also, even if there SocketException arises you can identify the exception for socket disconnection.
Hope this helps solve your problem.
I know this is late but I came up with a cunning solution for this.
I had to communicate with 3rd party software which expected a carriage return on every command sent, otherwise it ignored it.
During the main phase my client socket was in a loop receiving responses from the 3rd party software. My solution isn't ideal but the basic premise is that I put a receive timeout on the socket so that the loop will try to read for 5 seconds then fall into the catch, then loop again. Before each receive I call my own isconnected method which performs a small write without a carriage return, so it's ignored by the 3rd party software yet will give me a reliable fallover if the network has dropped. All I do if the write fails is throw a LostConnectionException and handle that externally.
If you are writing both server and client, you can quite easily come up with some checkdigit that the other ignores.
This may not be perfect but it's reliable for me.
while (numberOfBytesRead == 0)
{
try
{
IsConnected();
_socket.ReceiveTimeout = 5000;
numberOfBytesRead = _socket.Receive(myReadBuffer, 0, myReadBuffer.Length, SocketFlags.None);
}
catch (Exception e)
{
if (e.GetType() == typeof (LostConnection))
{
Status = SocketStatus.offline;
throw;
}
}
}
and the isconnected method would look something like this
public bool IsConnected(Socket s)
{
try
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("test");
s.Send(buffer, 0, buffer.Length, SocketFlags.None);
}
catch (Exception)
{
throw new LostConnection();
}
return s.Connected;
}

.NETCF Async TCP socket graceful shutdown issue

I have a TCP client/server app to communicate with a Windows CE device over an ActiveSync connection. Both the client and server utilize Asynchronous sockets (i.e. the Socket.Begin* and Socket.End* functions). When both the client and server are running on my desktop everything functions exactly as expected, but when the client is running on the Windows CE device that's connected over ActiveSync, I always get a SocketException on the ReceiveCallback after calling Socket.Shutdown (when the device is initiating the disconnect). The full exception is:
System.Net.Sockets.SocketException: An error message cannot be displayed because an optional resource assembly containing it cannot be found
at System.Net.Sockets.Socket.ReceiveNoCheck()
at ReceiveAsyncRequest.doRequest()
at AsyncRequest.handleRequest()
at WorkerThread.doWork()
at WorkerThread.doWorkI()
at WorkItem.doWork()
at System.Threading.Timer.ring()
Everything also seems to work correctly if the server (running on the desktop) initiates the disconnect. I have a couple ideas on how to avoid this, including disallowing device initiated disconnects and ignoring all exceptions after initiating a disconnect. However, I'd like to know why this is happening and if there's a better way of handling it.
The Disconnect and ReceiveCallbacks (operationally identical on both the server and client) are:
public bool Disconnect(StateObject state)
{
try{
if(state.isDisconnecting) return false;
state.isDisconnecting = true;
state.sock.Shutdown(SocketShutdown.Both);
//Wait for sending and receiving to complete, but don't wait more than 10 seconds
for(int i=0; i<100 && (state.isSending || state.isReceiving); i++){
System.Threading.Thread.Sleep(100);
}
/* Log the disconnect */
state.sock.Close();
return true;
} catch (Exception e){
/* Log the exception */
return false;
}
}
private void ReceiveCallback(IAsyncResult iar)
{
StateObject state = (StateObject)iar.AsyncState;
try{
//handle the new bytes in the buffer.
int recv = state.sock.EndReceive(iar);
//Handle the buffer, storing it somewhere and verifying complete messages.
if(recv > 0){
//start listening for the next message
state.sock.BeginReceive(state.recvBuffer, 0, StateObject.BUFFER_SIZE, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
} else {
state.isReceiving = false;
Disconnect(state);
}
} catch (Exception e){
/* Log the exception */
}
}
//For reference, A StateObject looks kinda like this:
public class StateObject
{
public const int BUFFER_SIZE = 1024;
public Socket sock = null;
public bool isSending = false;
public bool isReceiving = false;
public bool isDisconnecting = false;
public byte[] recvBuffer = new byte[BUFFER_SIZE];
public byte[] sendBuffer = new byte[BUFFER_SIZE];
//Other stuff that helps handle the buffers and ensure complete messages,
// even when TCP breaks up packets.
}
It in order to get the actual exception maybe try figure out which library it needs and deploy it?
If a message connot be shown on your device, because the message is not installed on your device. You have to install a netcf.messages.cab. You will find it here:
C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics
After installing this CAB-File, run your application again and post the new error you get.

Categories