如何停止抛出SocketException:“通过调用WSACancelBlockingCall中断了阻塞操作”?

6

请帮我解决以下异常:

System.Net.Sockets.SocketException:“执行阻止操作被WSACancelBlockingCall调用中断”

  1. 下面的代码实现了什么功能:向服务器发送UDP消息并获取回复(NAK或ACK)

  2. 抛出异常的代码:m_receiveBytes = m_receiver.Receive(ref m_from);

代码如下:

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();
        }
    }
}
1个回答

4
如果我正确理解您的代码,您正在启动一个线程来接收UDP消息。如果它接收到消息,它会设置一个事件。主线程启动该线程,然后等待最多五秒钟以设置事件。如果在此期间内事件未被设置,则主线程将销毁线程正在等待的接收器。
这肯定会抛出异常。
如果您想避免异常,请修改您的ThreadProc。
try
{
    // do stuff here
}
catch (SocketException) // or whatever the exception is that you're getting
{
}

我建议您不要在finally部分中包含m_mre.Set()的调用。主线程在等待完成后调用事件上的Reset,无论是否超时。如果线程在finally中调用Set,则如果发生超时,事件的状态将被设置,因为会出现以下情况:

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

相反,将您的主线程代码更改为以下内容:

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();
}

话虽如此,您并不需要启动一个线程来完成这个任务。相反,您可以利用UdpClient的异步能力。像这样:

// 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.
}

非常感谢,我会尝试您的建议,并给您反馈。 - user852194
嗨Jim,我尝试了你下面的逻辑,但不幸的是仍然出现相同的错误。 - user852194
@user852194:您收到的确切异常是什么?catch是否真正捕获了异常? - Jim Mischel
是的,同一个:阻塞操作被WSACancelBlockingCall调用中断。 - user852194
@user852194:这是异常的文本。实际的异常类型是什么?是 SocketException 吗?还是其他什么? - Jim Mischel
嗨Jim,我刚刚检查了我的数据库日志,这是问题的主要来源:System.Net.Sockets.SocketException:在数据报套接字上发送的消息大于内部消息缓冲区或其他网络限制,或用于接收数据报的缓冲区小于数据报本身。 - user852194

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接