Detecting Remote Client Socket Close in BeginReceive

O

O.B.

In the following code snippet, the thread successfully makes it to the
line where it waits for data to be received. Then the client closes the
connection. The thread wakes up and returns from the WaitOne()
operation. No exception is thrown when it loops and executes
BeginReceive() again. The WaitOne() operation returns immediately.
Thus, there's an endless loop.

How does one detect that the remote client has closed the connection in
this situation?


//
// Started as a new thread to handle data received on an
// open socket.
//
private void ReceiveDataEventLoop(Socket clientSocket) {
while (true) {
try {
ClientState clientState = new ClientState(clientSocket);
IAsyncResult result = clientSocket.BeginReceive(
clientState.Buffer,
0,
clientState.Buffer.Length,
SocketFlags.None,
new AsyncCallback(this.ReceiveDataCallback),
clientState);

// Wait for the EndReceive before issuing a new BeginReceive
// When the remote client closes the connection, this starts
// to return immediately. How to identify that remote client
// closed connection?
result.AsyncWaitHandle.WaitOne();

} catch (SocketException) {
removeSocket(clientSocket);
break;
} catch (Exception) {
removeSocket(clientSocket);
break;
}
}
}
 
O

O.B.

OK. I have a workaround:

Instead of using "result.AsyncWaitHandle.WaitOne()", I created a
ManualResetEvent and passed it to the BeginReceive delegate. When the
BeginReceive delegate starts, it gets the number of bytes when it calls
EndReceive. If 0, the BeginReceive delegate closes the socket. After
processing the data, the ManualResetEvent is set. Thus, when the
ReceiveDataEventLoop wakes up, it will try to access a disposed object
when it calls BeginReceive and then exit from its event loop.
 
P

Peter Duniho

O.B. said:
[...]
How does one detect that the remote client has closed the connection in
this situation?

As you have found, the receive function returns a bytes received value of 0
when the connection is closed.

However, your problem has less to do with that, than that you have created
an infinite loop that tries to receive over and over again without any means
of checking the socket for validity.

It seems to me that if you insist on this design, then the BeginReceive
method *ought* to throw an exception once your socket has been closed. That
is, after receiving 0 for the return value for EndReceive, you ought to be
able to just close the socket there, causing an exception here and allowing
the loop to exit.

However, in that case you don't have a direct means of knowing whether the
connection was closed normally or abnormally. IMHO, it would be better to
not have this design in the first place, requeuing the receive *only* when
you know you have successfully completed the previous receive (that is, in
the same code where you call EndReceive).

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top