I'm learning netcode and multithreading in Monodevelop, using C# with GTK#. I've never done either before, and now I find myself needing to do both at once.
I've used a tutorial chat program that has no error handling, and I've caught an error that happens in the client every single time I disconnect from the server. The code that sits in a thread listening for messages is as follows, surrounded by try/catch statements:
try
{
while (Connected)
{
if (!srReceiver.EndOfStream && Connected)
{
string temp = srReceiver.ReadLine();
// Show the messages in the log TextBox
Gtk.Application.Invoke(delegate
{
UpdateLog(temp);
});
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
After which the function finishes and the thread ends.
The code that ends the connection looks like this, and runs on the main thread:
private void CloseConnection(string Reason)
{
// Show the reason why the connection is ending
UpdateLog(Reason);
// Enable and disable the appropriate controls on the form
txtIp.Sensitive = true;
txtUser.Sensitive = true;
txtMessage.Sensitive = false;
btnSend.Sensitive = false;
btnConnect.Label = "Connect";
// Close the objects
Connected = false;
swSender.Close();
srReceiver.Close();
tcpServer.Close();
}
And the try/catch statements above catch this error:
System.IO.IOException: Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall. ---> System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.IO.StreamReader.ReadBuffer()
at System.IO.StreamReader.get_EndOfStream()
at ChatClientGTK.MainWindow.ReceiveMessages() in g:\Android\Tutes\ChatClientRemake\ChatClientGTK\MainWindow.cs:line 157
Now, as far as I can tell, when srReciever.Close() happens in the main thread, srReciever.ReadLine() is still trying to execute in the listening thread, which is where the problem lies, but even when I comment out srReciever.Close(), I still get the error.
As far as I can tell, there are no side-effects caused by just catching the error and moving on, but that doesn't really sit right with me. Do I need to fix this error, and if so, does anyone have any ideas?
Instead of using a ReadLine, can't you just do a Read and build up the String until a CrLf is detected then output that to update log.
ReadLine is a blocking call meaning it will sit there and always error if the connection is closed.
Otherwise you could just ignore the error. I know what you mean when you say it doesn't sit right but unless anyone else can enlighten me, I don't see that there is any leak in resources due to it and if it is an expected error then you can handle it appropriately.
Also I would probably catch the specific exception
catch (IOException ex)
{
Console.WriteLine(ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
The error is fine. If you really want it to go away, you can include a "bye" command in your protocol. So, if the server decides to disconnect, right before disconnecting he sends a "bye" to the client, so the client disconnects too, and most chances are that the exception will not be thrown. But you should still be prepared to catch it if it ever gets thrown. And then ignore it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With