异步TCP操作期间的AccessViolation

时间:2014-03-05 04:52:25

标签: c# sockets asynchronous tcp async-await

在各种异步TCP操作期间,我不断处理未处理AccessViolationException。 只有在内置函数的反汇编窗口中才会出现异常 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)。异常的堆栈跟踪仅包含此功能。装配线是:cmp dword ptr [ecx], ecx
最烦人的是异常到达不正常(程序可以执行30分钟或6小时或15秒)。

以下是完整的异常说明:

System.AccessViolationException unhandled
  HResult=-2147467261
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=mscorlib
StackTrace:
   in System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
InnerException: 

代码: 在任何尝试以任何方式访问TCP套接字异步期间,我都遇到此异常。我不使用外部非托管代码。这是我最后一次尝试以异步方式连接到远程地址组。

class Program
{
    static void Main(string[] args)
    {
        PollerCore p = new PollerCore();

        p.Start();
        Console.ReadLine();
    }
}
public class PollerCore
{
    string[] ip = new string[255];
    public void Start()
    {
        for (int i = 1; i < 255; i++)
        {
            ip[i] = String.Format("192.168.100.{0}", i);
        }
        new Thread(WorkerThread).Start();

    }

    async void WorkerThread()
    {
        while (true)
        {
            Console.WriteLine("In wt... ");
            DateTime dt = DateTime.Now;

            List<Task<string>> tasks = new List<Task<string>>();

            foreach (string addr in ip)
            {
                if (String.IsNullOrEmpty(addr)) continue;
                tasks.Add(ConnectToDevice(addr));
            }
            string[] res = await Task.WhenAll(tasks.ToArray());

            foreach (string s in res)
            {
                if (s != null) Console.WriteLine("Connecting to {0}... DONE", s);
            }
            Thread.Sleep(100);
        }
    }

    async Task<string> ConnectToDevice(string ip)
    {
        using (TcpClient c = new TcpClient())
        {
            try
            {
                await c.ConnectAsync(ip, 5100);
                return ip;
            }
            catch
            {
                return null;
            }
        }
    }

}

更新: 根据 Noseratio 建议重新编写代码中引发的相同异常。 Thread.Start已替换为Task.Run。在

catch
{
    return null;
}

我只收到代码为10060(超时)的SocketExceptions ...

1 个答案:

答案 0 :(得分:1)

我认为问题可能在这里:

new Thread(WorkerThread).Start();

// ...

async void WorkerThread() 
{
    // ...
}

尝试将其更改为:

var task = Task.Run(() => WorkerThreadAsync());
task.Wait(); // for debugging

// ...

async Task WorkerThreadAsync() 
{
    // ...
}

或者,根本不要使用单独的线程:

var task = WorkerThreadAsync();
task.Wait(); // for debugging

无论如何,您在WorkerThread内使用异步API,在第一个await之后很可能会切换到另一个池线程。

还有一些事情:

  • 不要这样做:catch { return null }。转储实际的异常信息。
  • TcpClient任务完成后,即一旦客户端连接到服务器后,您就会处置ConnectAsyncusing (TcpClient c = new TcpClient()) { ... }。你之后真的不再使用TcpClient对象吗?