WSACancelBlockingCall 异常

54

好的,我的代码抛出了一个奇怪的异常,一直困扰着我。

System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall
   at System.Net.Sockets.Socket.Accept()
   at System.Net.Sockets.TcpListener.AcceptTcpClient()

在这方面,MSDN的帮助并不是很有用:http://msdn.microsoft.com/en-us/library/ms741547(VS.85).aspx ,而且我甚至不知道如何开始解决这个问题。这个异常每天只会抛出4或5次,在我们的测试环境中从未出现过。只在生产站点上出现,并且在所有生产站点上都会出现。

我找到了很多关于这个异常的帖子,但没有实际的确定答案来解释它的原因以及如何处理或预防它。

代码在一个单独的后台线程中运行,方法开始:

public virtual void Startup()
    {
     TcpListener serverSocket= new TcpListener(new IPEndPoint(bindAddress, port));    
        serverSocket.Start();

然后我运行一个循环,将所有新连接作为工作放入一个单独的线程池中。由于应用程序的架构问题,情况变得更加复杂,但基本上如下:

然后我运行一个循环,将所有新连接作为任务放入一个独立的线程池中。由于应用程序的架构问题,这使情况变得更加复杂,但基本上如此:

   while (( socket = serverSocket.AcceptTcpClient()) !=null) //Funny exception here
    {
         connectionHandler = new ConnectionHandler(socket, mappingStrategy);
         pool.AddJob(connectionHandler);
    }
  }

从那里开始,pool有它自己的线程来独立处理每个任务。

我的理解是AcceptTcpClient()方法是一个阻塞调用,而winsock会告诉线程停止阻塞并继续执行...但为什么?我应该怎么做?只需捕获异常并忽略它吗?


我认为其他一些线程正在关闭该套接字,但肯定不是我的代码。 我想知道的是:这个套接字是由连接的客户端(套接字的另一侧)关闭还是由我的服务器关闭。因为目前情况下,每当发生此异常时,它就会关闭我的监听端口,有效地关闭我的服务。如果这是从远程位置完成的,则是一个重大问题。

或者,这是否仅仅是IIS服务器关闭了我的应用程序,从而取消了我的所有后台线程和阻塞方法?

5个回答

55

服务器套接字是否可能在另一个线程中被关闭?这会导致此异常。


说它是什么。如何从另一个线程关闭它?套接字需要被声明为“volatile”吗? - zkwentz
3
只要另一个线程有套接字对象的引用,它就可以关闭它。 - TimK

7
这是一个避免WSAcancelblablabla问题的示例解决方案: 将您的线程定义为全局变量,然后您可以像这样使用invoke方法:
private void closinginvoker(string dummy)
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action<string>(closinginvoker), new object[] { dummy });
            return;
        }
        t_listen.Abort();
        client_flag = true;
        c_idle.Close();
        listener1.Stop();
    }

在调用它之后,首先关闭线程,然后关闭永久循环标志以阻止进一步等待(如果有的话),然后关闭tcpclient并停止监听器。


1
InvokeRequired将你的解决方案绑定到winforms。如果代码正在运行Windows服务中,该怎么办? - Micah Epps

6
这可能会在serverSocket.Stop()时发生,我在每次调用Dispose时都会调用它。
以下是我的侦听线程异常处理的示例:
try
{
    //...
}
catch (SocketException socketEx)
{    
    if (_disposed)
        ar.SetAsCompleted(null, false); //exception because listener stopped (disposed), ignore exception
    else
        ar.SetAsCompleted(socketEx, false);
}

现在发生的情况是,在_disposed被设置为true之前,偶尔会出现异常。因此,对我来说解决方案就是使所有内容都线程安全。


3

我也遇到了同样的问题!但是我发现,服务器端的ReceiveBuffer被客户端堵塞了!(在我的情况下,是一些RFID扫描仪,它们不停地发送TagCode,而不是直到下一个TagCode到达前停止发送)

增加ReceiveBuffers并重新配置扫描仪有所帮助...


0

最近我在使用HttpWebRequest上传大文件时遇到了这个异常,而且超时时间已经过去了。

根据我的观察,只要上传时间超过3秒钟,就会导致出现这个错误。

string path = "Reasonably large file.dat";
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
System.Net.HttpWebRequest req = (HttpWebRequest)System.Net.HttpWebRequest.Create("Some URL");
req.Method = "PUT";
req.Timeout = 3000; //3 seconds, small timeout to demonstrate
long length = new System.IO.FileInfo(path).Length;
using (FileStream input = File.OpenRead(path))
{
    using (Stream output = req.GetRequestStream())
    {
        long remaining = length;
        int bytesRead = 0;
        while ((bytesRead = input.Read(buffer, 0, (int)Math.Min(remaining, (decimal)bufferSize))) > 0)
        {
            output.Write(buffer, 0, bytesRead);
            remaining -= bytesRead;
        }
        output.Close();
    }
input.Close();
}

嗯,我不太清楚这怎么能帮到我(我也遇到了同样的错误)。顺便说一下,“using”模式已经为您调用了output.Close();input.Close();,所以不需要自己再做一遍,否则会被调用两次。 - ForceMagic

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