Как мне остановить исключение SocketException: «Операция блокировки была прервана вызовом WSACancelBlockingCall» от выброса?

#c#

#c#

Вопрос:

Не могли бы вы помочь мне избавиться от этого исключения:

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:UDPmsgArchiveUDPmsg_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:

Если я правильно читаю ваш код, вы запускаете поток для получения UDP-сообщения. Если он получает сообщение, он устанавливает событие. Основной поток запускает поток, а затем ожидает до пяти секунд, пока событие будет установлено. Если событие не задано в течение этого времени, основной поток уничтожает приемник, которого ожидает поток.

Это определенно вызовет исключение.

Если вы ждете устранения исключения, измените ThreadProc

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

Я бы посоветовал вам не включать m_mre.Set() звонок в finally раздел. Основной поток вызывает Reset событие после завершения ожидания, независимо от того, есть ли тайм-аут или нет. Если поток вызывает Set finally, состояние события будет установлено, если произойдет тайм-аут, потому что происходит следующее:

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

Комментарии:

1. Очень признателен, я попробую ваше предложение и дам вам отзыв

2. Привет, Джим, я пробую вашу логику ниже, но, к сожалению, все та же ошибка.

3. @user852194: Какое именно исключение вы получаете? catch Действительно ли это улавливает исключение?

4. да, тот же самый: операция блокировки была прервана вызовом WSACancelBlockingCall .

5. @user852194: Это текст исключения. Каков фактический тип исключения? Так ли это SocketException ? Что-то еще?