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 :)
Related
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
}
}
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?
I've built a C# application which reads and writes data from a serial port. The device connected to the serial port is a FTDI USB to serial converter which communicates to hardware through a XBee wireless module. The hardware tests battery modules for capacity and steady state voltage etc. these tests take days to complete.
Every now and then the serial port seems to stop responding and throws a System.IO.IOException: A device attached to the system is not functioning error.
Here is the stack trace:
at system.IO.Ports.InternalResources.WinIOError
at system.IO.Ports.SerialStream.EndWrite
at system.IO.Ports.SerialStream.Write
at system.IO.Ports.SerialPort.Write
at BatteryCharger.CommunicationClass.ApiTransmission
after this error is thrown a System.UnauthorizedAccessException: Access to the port is denied error is thrown and this error occurs every time the software tries to write to the port and it never recovers until i stop debugging and restart the software only for the same thing to happen a few days later.
How do I prevent this error from occurring or is there a way to successfully recover from these errors in the catch statement of the error?
I'm reading the serial port continuously in a background worker thread and writing from a different thread.
I've also already tried all the legacy error handling bits and pieces that have been suggested on this forum but none of them seem to make any difference. The error occurs on windows XP Pro SP3 32bit and Windows7 Pro 32bit.
Here is the CommunicationClass.cs - serial transmission code.
public static bool ApiTransmission(TXpacket transmission)
{
//clear all previous data that may have been in the buffer before doing a transmission
Variables.dataParserPacket_buff.Clear();
//TXpacket xbeetransmision = new TXpacket();
byte[] packet = transmission.GeneratePacket();
try
{
if (_serialPort.IsOpen)
{
#if Console
Log.write("TX-Packet: " + StringHandler.listToString(packet.ToList<byte>()));
#endif
_serialPort.Write(packet, 0, packet.Length);
Thread.Sleep(100);
}
else
{
#if Console
Log.write("serial port is closed");
#endif
return false;
}
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.ToString());
Log.write("UnauthorizedAccessException");
}
catch (IOException ex)
{
MessageBox.Show(ex.ToString());
Log.write("IOexception");
//_serialPort.Close();
//Thread.Sleep(100);
//_serialPort.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
#if Console
Log.write(ex.ToString());
#endif
}
return true;
}
This is how I initialize my serial port
public CommunicationClass(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
{
_analysePacketBGW.DoWork += new DoWorkEventHandler(_analysePacketBGW_DoWork);
_analysePacketBGW.WorkerReportsProgress = true;
_analysePacketBGW.WorkerSupportsCancellation = true;
_readBGW.DoWork += new DoWorkEventHandler(_readThread_DoWork);
_readBGW.WorkerSupportsCancellation = true;
_readBGW.WorkerReportsProgress = true;
_parserStarterBGW.DoWork += new DoWorkEventHandler(_parserStarterThread_DoWork);
_parserStarterBGW.WorkerSupportsCancellation = true;
_parserStarterBGW.WorkerReportsProgress = true;
if (_readBGW != null)
{
_readBGW.CancelAsync();
}
_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
//SerialPortFixer.Execute(portName);
//Thread.Sleep(1000);
//using (_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits))
//{
// //_serialPort.Open();
//}
_serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(_serialPort_ErrorReceived);
_dataqueuepp = new ManualResetEvent(false);
_serialPort.Open();
_readBGW.RunWorkerAsync();
_parserStarterBGW.RunWorkerAsync();
CommunicationClass.PacketReceived += new DataPacketReceived(CommunicationClass_PacketReceived);
}
And the background worker that handles the reading of the serial port
void _readThread_DoWork(object sender, DoWorkEventArgs e)
{
#if Console
Log.write("Read()");
#endif
while (!_readBGW.CancellationPending)
{
try
{
int message = _serialPort.ReadByte();
try
{
Variables.dataQueue.Enqueue(message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " " + message.ToString());
}
_dataqueuepp.Set();
//Console.Write(String.Format("{0:X2}", message) + " ");
}
catch (TimeoutException) { Log.write("read timeout"); }
catch (IOException) { Log.write("read IOException"); }
catch (ThreadAbortException) { Log.write("read thread aborted"); }
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
finally { }
}
}
I will now rewrite the code to read and write to/from the serial port from the same thread to see if that makes any difference.
EDIT
Based on Jim's comments I've added the following to the IOException Catch statement:
catch (IOException ex)
{
MessageBox.Show(ex.ToString());
Log.write("IOexception");
_readBGW.CancelAsync();
Thread.Sleep(100);
_serialPort.Close();
Thread.Sleep(100);
_serialPort.Open();
Thread.Sleep(100);
_readBGW.RunWorkerAsync();
_serialPort.Write(packet, 0, packet.Length);
}
Hopefully by stopping the background worker's _serialPort.Read, closing the port, re-opening the port, running the background worker again and attempting to write the same command again will be enough to successfully recover from this error. The MessageBox still blocks the code so that i can see when the error occurs and can monitor how it recovers.
I don't like patching software like this but if it works then it works.
EDIT 2
After adding the code above my software crashed again but now it throws an "UnauthorizedAccessException - Access to the port is denied" when i call _serialPort.Close();
System.UnauthorizedAccessException was unhandled
Message=Access to the port is denied.
Source=System
StackTrace:
at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
at System.IO.Ports.InternalResources.WinIOError()
at System.IO.Ports.SerialStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Ports.SerialPort.Dispose(Boolean disposing)
at System.IO.Ports.SerialPort.Close()
at BatteryCharger.CommunicationClass.ApiTransmission(TXpacket transmission) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\CommunicationClass.cs:line 436
at BatteryCharger.CommunicationClass.tx1(TXpacket packet, String callingMethod) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\CommunicationClass.cs:line 356
at BatteryCharger.XBee.setPin(String pinID, Byte status, XBee slave) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\XBee.cs:line 215
at BatteryCharger.XBee.setPins(Int32 pins, XBee slave) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\XBee.cs:line 177
at BatteryCharger.BatteryCharger.requestVoltage(Int32 block) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\BatteryCharger.cs:line 595
at BatteryCharger.BatteryCharger.requestVoltages() in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\BatteryCharger.cs:line 612
at BatteryCharger.Form1.RunCommandOn(List`1 battList, Int32 command, Double lowerLimit, Double upperLimit) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 522
at BatteryCharger.Form1.chargeBlock(Int32 blockNr, Double lowerLimit, Double upperLimit) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 689
at BatteryCharger.Form1.<btnCheckCapacities_Click>b__13() in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 619
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
What is going on here?
In my experience 9 times out of 10 this happens when another thread (terminated or not) doesn't have exclusive access to the hardware port.
Try writing a wrapper for the port operations, most importantly the open/closing of it, using SyncLock. https://msdn.microsoft.com/en-us/library/3a86s51t.aspx
On a similar note, I would generally consider try/catches controlling hardware a bad practice, unless there's adequate exception handling.
The reason (which could apply here) is that in the case where an exception is thrown the hardware will lock, and what is worse, the exception will mask the true cause of the error(s).
In the code above I see output of messages in the style
DebugPrint(ex.Message);
it would be quite better to do this like
DebugPrint(ex.tostring());
as this will also export the stack trace in the exception.
What I would do is implement an exception logger that writes those exceptions to a (time stamped) text file somewhere in the computer this is running. Following on the exception data logged (along with all pertinent information) can lead to a better understanding why exactly this happens.
I use intensively SerialPort class to communicate continuously with PLCs through USB Adapters for months without any break. So I cannot agree who says SerialPort .NET class does not work. Try to insert creation of class into thread, here is a sample of code with BackgroundWorker.
void ThreadEngine_DoWork(object sender, DoWorkEventArgs e)
{
// Do not access the form's BackgroundWorker reference directly.
// Instead, use the reference provided by the sender parameter.
BackgroundWorker objBackgroundWorker = sender as BackgroundWorker;
try
{
mSerialPort = new SerialPort(GetPortName(mPortName), DefaultBaudRate, Parity.Even, 7, StopBits.Two);
mSerialPort.Open();
objBackgroundWorker.ReportProgress(0);
while (objBackgroundWorker.CancellationPending == false)
{
if (IOScanner(objBackgroundWorker, false) == true)
{
ScannerStationData();
IsReady = true;
IsError = false;
}
else
{
IsReady = false;
IsError = true;
}
Thread.Sleep(1);
}
// Performs last scan before thread closing
if (objBackgroundWorker.CancellationPending == true)
{
IOScanner(objBackgroundWorker, true);
}
mSerialPort.Close();
mSerialPort = null;
e.Result = null;
}
catch (Exception objErr)
{
string sMessage = string.Format("PlcService.ThreadEngine_DoWork Err={0}", objErr.Message);
mLogSysService.AddItem(sMessage);
IsError = true;
}
}
Method IOScanner calls other methods for to communicate like following one.
protected bool WriteDMWord(int iAddress, int[] aryValues)
{
bool bRetValue = true;
try
{
mSerialPort.NewLine = "\r";
mSerialPort.ReadTimeout = DefaultTimeout;
string sTxData = HostLinkProtocol.BuildWriteDMWord(iAddress, aryValues);
mSerialPort.WriteLine(sTxData);
string sRxData = string.Empty;
sRxData = mSerialPort.ReadLine();
if (HostLinkProtocol.ParseWriteDMWord(sRxData) == true)
{
bRetValue = true;
}
}
catch (Exception objErr)
{
Console.WriteLine("WriteDMWord [{0}]", objErr.Message);
bRetValue = false;
}
return bRetValue;
}
I use a FTDI USB, and I communicate with it on Serial .net class, sometimes on WindowsXp I have this kind of exception, I solve it with devcon.exe, I perform disable and enable and the error did not appears.
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;
}
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);