Cancelling an async invoke

Bucky

Contributor
Joined
Dec 23, 2001
Messages
791
Location
East Coast
In writing code to handle the listening and connection-accepting
of a Socket instance, I've run into a snag after calling
BeginAccept. After calling BeginAccept, I want to be able to cancel
the calling of my callback function and essentially stop the Socket
from listening before it actually receives a connection request.

When a connection request does come, the Socket accepts it,
receives from it, and closes it fine, but I'd like to be able to stop
the Socket from listening before a connection is requested.

GavinO suggested a very creative kludge that invoves creating a
new Socket and connecting with listening one so that the
connection would be made (behind the scenes) and then
successfully closed right away. Needless to say, I'm hoping
there's a more elegant way. :)

Oh, and this is the code I'm using to start the accept callback:
C#:
IAsyncResult beginAcceptResult;
beginAcceptResult = listenSocket.BeginAccept(new AsyncCallback(ListenCallback), null);

Thanks.
 
I have tried each and both of these methods, with no success.

Calling Shutdown first raises a SocketError when I try to Close or
dispose of the Socket, quote, "A request to send or receive data
was disallowed because the socket is not connected and (when
sending on a datagram socket using a sendto call) no address
was supplied".

Just calling Close raises an InvalidOperationException that only
says "AcceptCallback", and it points to a location in the
disassembly, though Close is what causes it.
 
Are you sure the exception isn't being thown by EndAccept when you call it from your async handler, because you've just shut down the socket? In which case you'd want to just trap the exception and move on.
 
EndAccept never gets a chance to be called. When calling
Shutdown, the error points to the line
C#:
listenSocket = null;

When calling Close, there is only a disassembly location for the error.
 
You could always cheat and set a flag to specify whether the code within the EndInvoke is executed or not.

private bool flag = true;
private void EndCallback(IAsyncResult result){
if(flag){
..... execute code....
}

}
 
Yes, but then I cannot call Close and then Listen on the same
port, because a socket will still be bound to that port.
 
I am experiencing the same problem.

It's really strange, has anyone made any advances in this?
 
How to cancel asynchronous socket accept calls.

Right firstly, Bucky.
When you call close on an accepting socket, the asynchronous request is triggered as completed with an invalid socket, therefore when your program calls EndAccept it tries to access a non-existant socket and causes the EndAccept exception.

As Rodenburg suggested a flag can be used to catch when this occurs so that you don't call EndAccept in these cases. However there is another way.

The IAsyncResult parameter that is passed to the function contains the data about the socket that accepts the connection. I.e. A member of IAsyncResult contains the socket returned by EndAccept. This member is AsyncState. If you cast this to a socket, then you can look at the underlining handle for the socket to see if it is valid (>= 0) or invalid (-1). If the handle is -1 then the accept call was cancelled.

Example....

private void AcceptSmtp(IAsyncResult ar)
{
Socket test = (Socket)ar.AsyncState; // Cast the result to a socket.
if (test.Handle.ToInt32() == -1) // Check if the handle is invalid.
{
return; // Exit as the call was cancelled.
}

// If we get here then this is an actual accept.
Socket client = smtpListener.EndAccept(ar); // Get the socket.

........
}

Hope this helps you all, Mike Nimmo.
 
As a quick update, it appears that EndAccept must be called within the asynchronous function but if the socket is invalid then you can call EndAccept within a trap.
 
Actually, I've never encountered that problem.

To close down the listening socket:

Code:
	if (serverThread != null)
			{
				if (serverThread.IsAlive)
				{
					if (listeningSocket.Connected)
					{
						listeningSocket.Shutdown(System.Net.Sockets.SocketShutdown.Both);
						listeningSocket.Close();
					}

					serverThread.Abort();
				}
			}


When calling BeginAccept, why do you save the AsyncResult? The AsyncResult is passed to the EventHandling function.


Try:

private static System.Threading.ManualResetEvent allDone = new System.Threading.ManualResetEvent(false);

while (true)
{
allDone.Reset();
listeningSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
allDone.WaitOne();
}

private void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
socket = listeningSocket.EndAccept(ar);
}
 
Last edited:
Back
Top