Thursday, April 15, 2010

Solve Exception Message: The IAsyncResult object was not returned from the corresponding asynchronous method on this class

Recently I was got a weird error on my Windows CE code (.NET compact framework) which was asynchronously listening for UDP (or may be same for TCP) messages.

Exception Message

Error Message: The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
CallStack for debug purpose:
    at System.Net.Sockets.Socket.EndReceiveFrom()
    at BallyTech.SocketListener.UdpSocketListener.OnReceive()
    at System.Net.LazyAsyncResult.InvokeCallback()
    at WorkerThread.doWork()
    at WorkerThread.doWorkI()
    at WorkItem.doWork()
    at System.Threading.Timer.ring()

Issue

When frequently Open/Close UDP sockets, above exception comes while closing one socket and start listening on another socket on the same port. OnReceive method is called (only once) for the previous (closed) socket while doing “Start Listening” on new socket on the same port. As old socket is already dereferenced and closed, you will get above socket exception on EndReceiveFrom or EndReceive method.

Solution

In short, you have to ignore the calls of your OnReceive (or similar) for Old socket which you no longer use i.e. closed sockets.

Note that when you call BeginReceiveFrom to start listening for messages, it returns an instance of IAsyncResult. Don’t ignore this and store it into class level private variable (let’s say variable name currentAsyncResult).

Now make modification into  your OnReceive method to ignore any message which is not for currentAsyncResult.

private void OnReceive(IAsyncResult ar)
{
try
{
if (ar == currentAynchResult)
{
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
EndPoint epSender = (EndPoint)ipeSender;

//Error comes here if we didn't have (ar == currentAynchResult) check
int bytesRead = udpSocket.EndReceiveFrom(ar, ref epSender);
//process further
}
else
{
//Ignore
}
BeginReceive();
}
catch (Exception ex)
{
//Log exception. Don't throw exception. Most probably BeginReceive failed.
}
}

Notice the if (ar == currentAynchResult) check where we got currentAynchResult from BeginReceiveFrom method while starting listening from new socket.

Happy Networking!

9 comments:

Kevin said...

Hey man, thanks for the plan of action on this. I am still wondering how you declare a variable from the BeginReceiveFromMethod.

My code breaks, not all the time. So the solution is exactly as you describe - but I am doing things differently and I am very new to IAsync.

void ReceiveData(IAsyncResult iar)
{

Socket remote = (Socket)iar.AsyncState;

int recv = remote.EndReceive(iar);
if(iar == iar)
{
//to do here
}
}

What am I doing wrong?

Regards,
Kevin Heathfield

Yogee said...

private IAsyncResult oldAynchResult;
private void BeginReceive()
{
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
//The epSender identifies the incoming clients
EndPoint epSender = (EndPoint)ipeSender;

//Start receiving data
oldAynchResult = udpSocket.BeginReceiveFrom(DataBuffer, 0, DataBuffer.Length,
SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);
}


http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.beginreceivefrom.aspx


Your code,
if(iar == iar)
{
//to do here
}
will change to
if(iar == oldAynchResult)
{
//to do here
}

Anonymous said...

Cool. Thanks

Anonymous said...

hey hi i Vivek ,
I am also Facing same proablem ...IAsyncResult object was not returned from the corresponding asynchronous method

I am Following the Instruction As given below ..can someone suggest the needful

Yogee said...

Hi Vivek,
Read the comments too. You should have the check where you compare if AsynchResult is for current connection or it is from older one.
Or for a quick solution, write onReceive method like this

{
try
{
// your current code
}
finally
{
beginReceive();
}

I am not happy to give this solution but it will work.

Jc said...

I had this bug and found the solution...

I was calling connect twice, thus the 2nd receive was from the wrong socket, make sure you check that!

Yogee said...

That's a good point JC.

Anonymous said...

Where does currentAynchResult come from?

ar obviously gets passed in as an argument but its not clear where currentAynchResult comes from?

Thanks!

Yogee said...

Hi Anonymous, When you call BeginReceiveFrom to start listening for messages, it returns an instance of IAsyncResult. Don’t ignore this and store it into class level private variable, that's what i've called currentAsyncResult.