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!
11 comments:
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
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
}
Cool. Thanks
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
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.
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!
That's a good point JC.
Where does currentAynchResult come from?
ar obviously gets passed in as an argument but its not clear where currentAynchResult comes from?
Thanks!
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.
It helped me and I had exactly such a case. Thanks.
Thanks this helped alot
Post a Comment