C#: SocketException when Server closes? - c#

I'm currently receiving a strange error, and want to handle it for 1 specific case. When the server closes and the client is still connected to it, the client will throw an exception
System.Net.Sockets.SocketException: 'An existing connection was
forcibly closed by the remote host'
I know how to handle this, a try and catch, but am I handling more than one reason this exception would be thrown here? I just want to handle it if the server closes, not all of the other reasons this exception may suddenly occur. Can anybody help here?
What line is the error occuring on?
var bytesReceived = _socket.EndReceive(asyncResult);
What method?
private void OnIncomingData(IAsyncResult asyncResult)
Method content
var bytesReceived = _socket.EndReceive(asyncResult);
try
{
var packet = new byte[bytesReceived];
Array.Copy(_buffer, packet, bytesReceived);
var received = Encoding.UTF8.GetString(packet);
CoreUtilities.LogToConsole("Received data: " + received);
}
catch
{
Dispose();
}
finally
{
try
{
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, OnIncomingData, _socket);
}
catch
{
}
}

You could handle this using the SocketErrorCode property which part of SocketException. According to this TechNET article (I couldn't find anything on MSDN), the error code should be 10054 which matches with the SocketError.ConnectionReset enum value as shown below:
Example of handling the specific error:
try
{
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, OnIncomingData, _socket);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.ConnectionReset)
{
//Do Something
}
}

Related

Correct way to end serial port base stream reading

I've built a serial logger in c# using the solution from Ben Voigt
https://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport
byte[] buffer = new byte[blockLimit];
Action kickoffRead = null;
kickoffRead = delegate {
port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar) {
try {
int actualLength = port.BaseStream.EndRead(ar);
byte[] received = new byte[actualLength];
Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
raiseAppSerialDataEvent(received);
}
catch (IOException exc) {
handleAppSerialError(exc);
}
kickoffRead();
}, null);
};
kickoffRead();
All other methods I tried failed in one way or another (Ben Voigt explains extensively why on his excellent page). Now I'm only left with two questions:
1). How do I gracefully stop listening to the serial port? If I close the comport it will raise a nasty exception.
2). Is there an elegant way to raise an event if there is no data recieved for a certain time?

How to reconnect a TcpClient as soon as network unplugged and then plugged

I have a TcpClient that i want automatically re-connect as soon as network disconnects and then reconnect,but i am not getting how to achieve it..
Here is my function ..
private void Conn()
{
try
{
client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Parse(ip), intport));
//Say thread to sleep for 1 secs.
Thread.Sleep(1000);
}
catch (Exception ex)
{
// Log the error here.
client.Close();
}
try
{
using (NetworkStream stream = client.GetStream())
{
byte[] notify = Encoding.ASCII.GetBytes("Hello");
stream.Write(notify, 0, notify.Length);
}
byte[] data = new byte[1024];
while (true)
{
{
int numBytesRead = stream.Read(data, 0, data.Length);
if (numBytesRead > 0)
{
data= Encoding.ASCII.GetString(data, 0, numBytesRead);
}
}
}
}
catch{Exception ex}
Also how reliable is while (true) to get the continuous data from the Tcpip machine.Till my testing this codes automatically exits from responding or getting data after a while.
Please help me to get the uninterrupted data .
Thanks..
You are immediately disposing of the NetworkStream after you have written something. This closes the socket. Don't do that. Rather, put the TcpClient in a using statement.
The way you read data is exactly right. The loop will exit when Read returns 0 which indicated a graceful shutdown of the connection by the remote side. If this is unexpected, the problem lies with the remote side.
Catch SocketException only and examine the status code property to find out the exact error.
It is not possible to reliably detect network errors. You have to wait for an exception to notice connection failure. After that, you need to periodically try establishing a connection again to find out when the network becomes available again.
I believe Windows provides some network interface level events to detect unplugged cabled but those are unreliable.

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

c# exception not caught

I have a method that is a listener for a TCP client which looks like this:
private static void ProcessClient(
Object obj)
{
ISession session = (ISession)obj;
NetworkStream networkStream = null;
try
{
DebugUtility.SetThreadName("Worker: {0}", session.Name);
networkStream = session.TcpClient.GetStream();
networkStream.ReadTimeout = Config.ReadTimeout;
// Loop received packets (blocks untill next packet)
Int32 packetSize;
Byte[] buffer = new Byte[session.PacketSize];
while ((packetSize = networkStream.Read(buffer, 0, buffer.Length)) != 0)
{
// Get String from packet bytes
String packet = Encoding.UTF8.GetString(buffer, 0, packetSize);
// Check if packet has data
if (String.IsNullOrEmpty(packet))
continue;
// Log biggest received package
DebugUtility.CheckMaxPacketSize(session.Name, packet.Length);
// Handle packet (in new thread)
Logger.DebugLog("Received: {0}", packet);
ThreadPool.QueueUserWorkItem(session.HandlePacket, packet);
}
}
catch (ObjectDisposedException) { }
catch (NotSupportedException) { }
catch (TimeoutException) { }
catch (SocketException) { }
catch (IOException) { }
catch (Exception ex)
{
Logger.LogException(ex);
}
finally
{
if (networkStream != null)
networkStream.Close();
if (session != null)
session.Disconnect();
}
}
This is for a game service but when I check my logs, I occasionally see this error:
System.Int32 Read(Byte[], Int32, Int32): The stream does not support reading.
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at BusinessLayer.Listener.ListenerWorker.ProcessClient(Object obj) in C:\path\ListenerWorker.cs:line 141 Line: 0
That is the above described file and line 141 is
while ((packetSize = networkStream.Read(buffer,....
Now I have found that NotSupportedException is throwing this error, but why does it go through? Why is it not ignored but does it fall through the normal Exception ex handler?
Edit: Does anyone know how I can invoke this exception? When does it occur? I only see it coming back in my logs to other users, but I don't know when it happens.
Because NetworkStream.Read is throwing an InvalidOperationException, not a NotSupportedException (contrary to the documentation). You can confirm this from Reflector:
if (!this.CanRead)
{
throw new InvalidOperationException(SR.GetString("net_writeonlystream"));
}
Never ever ever swallow an exception unless you are 100% sure that you can do something about it and recover from it. Swallowing all exceptions implies that whatever happens your program can recover and continue. What if it's an OutOfMemoryException or a StackOverflowException, can you program handle those gracefully? Yes log the exception, but for the love of god, rethrow it and let it do its job :)

Handling timeout on blocking .NET socket

A TcpClient instance, created with the Accept method, is used for manage a client connection. The problem arise when I need to terminate the server thread, since it is blocked on a receive call.
So I setup a the TcpClient ReceiveTimeout in order to loop every n milliseconds to test the exit condition. The result is that the Receive operation raise an exception (SocketException) having the error code SocketError.TimedOut. Good I was thinking...
The problem is that the property Socket.Connected returns false, but as stated in the MSDN documentation:
The value of the Connected property reflects the state of the connection as of the most recent operation. If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.
So, I do what states:
try {
// Receive operation on socket stream
// Send operation on socket stream
} catch (SocketException e) {
if (e.SocketErrorCode == SocketError.TimedOut) {
try {
IAsyncResult asyncResult;
int sResult;
asyncResult = mSocket.Client.BeginSend(new byte[] {}, 0, 0, SocketFlags.None, delegate(IAsyncResult result) { }, null);
sResult = mSocket.Client.EndSend(asyncResult);
Debug.Assert(asyncResult.IsCompleted == true);
if (mSocket.Connected == false)
throw new Exception("not more connected"); // Always thrown
} catch (Exception e) {
// ...
}
}
But, even if the aynch Send operation is executed, the property mSocket.Connected is always false, causing the outer loop to terminate (other threads calls Disconnect method to terminate the server thread).
What am I missing?
The problem is if the timeout occurs the TcpClient gets disconnected. So your method won't work.
Use the async read/write functions or use select.
The probably easiest way with async function call is like this:
byte[] data = new byte[4096];
IASyncResult result = stream.BeginRead(data, 0, data.Length, null, null);
result.AsyncWaitHandle.WaitOne(<timeout value in ms>);
int bytes = stream.EndRead(result);
if (!result.IsCompleted)
<timed out>
else
<read data>
...
You should look at the C# example on the Socket.Connected MSDN page you linked to. It has a significantly different implementation of a method to determine whether the socket is still connected.
// .Connect throws an exception if unsuccessful
client.Connect(anEndPoint);
// This is how you can determine whether a socket is still connected.
bool blockingState = client.Blocking;
try
{
byte [] tmp = new byte[1];
client.Blocking = false;
client.Send(tmp, 0, 0);
Console.WriteLine("Connected!");
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
Console.WriteLine("Still Connected, but the Send would block");
else
{
Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
}
}
finally
{
client.Blocking = blockingState;
}
Console.WriteLine("Connected: {0}", client.Connected);

Categories