I'm experimenting with Sockets, and have built a fairly simple TCP server.
Code available here: http://pastebin.com/zLRaBc0q
I have a problem with stopping the Socket server from client. In the pastebin, starting on line 136
to 192
is the handler for server termination.
The logic behind is fairly simple:
The program executes the above perfectly, but it somehow manages to squeeze in one extra step at the end of it - seems to unexpectedly execute ReceiveCallback
(well, it's unexpected to me), and then ending up with ObjectDisposedException
for line 100
:
private static void ReceiveCallback(object sender, SocketAsyncEventArgs e)
{
Socket client = (Socket)sender;
Socket listener = (Socket)e.UserToken;
string message = Encoding.ASCII.GetString(e.Buffer, e.Offset, e.BytesTransferred);
// L100
// \/
IPEndPoint clientCoordinates = client.RemoteEndPoint as IPEndPoint;
IPEndPoint serverCoordinates = listener.LocalEndPoint as IPEndPoint;
Console.WriteLine("{0} bytes from {1} on {2}", e.BytesTransferred, clientCoordinates, serverCoordinates);
Obviously, that it cannot access at the shutdown process closed client
. The problem here is, I don't understand why the program even enters the ReceiveCallback
again. I return void after handling quit message without initiating another call to it.
Worth mentioning is that it only happens when there are two clients connected. With one client it stops without problems.
That though, depicts (to me), that it's not the requesting client
ending up with ObjectDisposedException
, but the other one. That still doesn't help me, because, anyways, I don't understand why there is ReceiveCallback
called again - the client was disconnected and should be marked as such before I stop the server.
How do I make the server stop without ObjectDisposedException
?
P.S. The parentheses with to me are just sidenotes. Since I'm a newbie to async + threading, I don't understand how some of the behaviors can happen.
The problem can be fixed by adding an extra check atop the callbacks:
// Handle errors.
if (e.SocketError != SocketError.Success)
{
Console.WriteLine("Socket error: {0}", e.SocketError.ToString());
return;
}
The SocketAsyncEventArgs.Completed
will run at all cases, but it's SocketError
will be set to different values.
In my case, it was set to SocketError.OperationAborted
(what is true), and I just had to do special handling - in my case, ignore it with a simple return;
.