Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I stop SocketException: "A blocking operation was interrupted by a call to WSACancelBlockingCall" from being thrown?

Tags:

c#

Could you help me to get rid of this exception:

System.Net.Sockets.SocketException: "A blocking operation was interrupted by a call to WSACancelBlockingCall"

  1. What the below code does: sends UDP message to the server and fetches reply (NAK or ACK)

  2. Code that throws exception: m_receiveBytes = m_receiver.Receive(ref m_from);

Code:

public partial class _Default : System.Web.UI.Page
{ 
    static readonly object lockScheduleIem = new object();
    IPAddress m_AddressSend;
    IPAddress m_AddressRecieve;
    int m_groupPortSend;
    int m_groupPortReceive;
    IPEndPoint m_IPAddressSend;
    IPEndPoint m_IPAddressReceive;
    Byte[] m_receiveBytes;
    Thread m_thread;
    UdpClient m_receiver;
    ManualResetEvent m_mre;
    UdpClient m_sender;
    IPEndPoint m_from;

    protected void Page_Init(object sender, EventArgs e)
    {
        m_AddressSend = IPAddress.Parse("10.43.60.177");
        m_AddressRecieve = IPAddress.Parse("10.43.60.99");

        int.TryParse("60200", out m_groupPortSend);
        int.TryParse("206", out m_groupPortReceive);

        m_IPAddressSend = new IPEndPoint(m_AddressSend, m_groupPortSend);
        m_IPAddressReceive = new IPEndPoint(m_AddressRecieve, m_groupPortReceive);

        m_mre = new ManualResetEvent(false);
        m_from = new IPEndPoint(IPAddress.Any, 0);
    }
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        try
        {
            TimeSpan timeout;
            timeout = new TimeSpan(0, 0, 0, 0, 5000);
            m_sender = new UdpClient();
            m_receiveBytes = null;
            m_receiver = new UdpClient(m_IPAddressReceive);
            m_thread = new Thread(new ThreadStart(ThreadProc));
            m_thread.Start();
            string str = string.Empty;
            using (StreamReader sr = new StreamReader(@"C:\UDPmsgArchive\UDPmsg_Of_2011_10_18_13_7_33_968_634545400539687500.xml"))
                str = sr.ReadToEnd();
            byte[] XMLbytes = Encoding.ASCII.GetBytes(str);
            m_sender.Send(XMLbytes, XMLbytes.Length, m_IPAddressSend);

            m_mre.WaitOne(timeout, true);
            m_mre.Reset();
            m_receiver.Close();

            if (m_receiveBytes != null)
                Response.Write(Encoding.ASCII.GetString(m_receiveBytes, 0, m_receiveBytes.Length));
            else
                Response.Write("string.Empty");
        }
        catch (Exception ex)
        {
            Response.Write(ex.ToString());
        }
    }

    public void ThreadProc()
    {
        try
        {
            m_receiveBytes = m_receiver.Receive(ref m_from); // ERROR HERE
            m_mre.Set();
            m_receiver.Close();
        }
        finally
        {
            m_mre.Set();
        }
    }
}
like image 958
user852194 Avatar asked Oct 24 '11 15:10

user852194


1 Answers

If I'm reading your code right, you're starting a thread to receive a UDP message. If it receives the message, it sets an event. The main thread starts the thread and then waits up to five seconds for the event to be set. If the event isn't set within that time, the main thread destroys the receiver that the thread is waiting on.

That's definitely going to throw an exception.

If you wait to eliminate the exception, modify your ThreadProc

try
{
    // do stuff here
}
catch (SocketException) // or whatever the exception is that you're getting
{
}

I would suggest that you not include the m_mre.Set() call in a finally section. The main thread calls Reset on the event after the wait has completed, whether or not there is a timeout. If the thread calls Set in the finally, the the event's state will be set if a timeout occurs, because the following happens:

main thread calls Reset()
main thread calls Close() on the client
ThreadProc calls Set() in the finally

Instead, change your main thread code to look like this:

if (m_mre.WaitOne(timeout, true))
{
    // event was set by the thread proc
    // process the received data
    // and reset the event
    m_mre.Reset();
}
else
{
    // A timeout occurred.
    // Close the receiver
    m_receiver.Close();
}

That said, you really don't have to spin up a thread to do this. Rather, you could use the asynchronous capabilities of UdpClient. Something like:

// Set timeout on the socket
m_receiver.Client.ReceiveTimeout = 5000;
try
{
    IAsyncResult ir = m_receiver.BeginReceive(null, null);
    m_receivedBytes = m_receiver.EndReceive(ir, m_receiver.Client.RemoteEndPoint);
    // process received bytes here
}
catch (SocketException)
{
    // Timeout or some other error happened.
}
like image 174
Jim Mischel Avatar answered Nov 17 '22 05:11

Jim Mischel