【问题标题】:UdpClient Exception on async reception only on Windows XP仅在 Windows XP 上异步接收的 UdpClient 异常
【发布时间】:2013-03-14 23:32:17
【问题描述】:

我的 c# 代码在 Windows vista/seven 中运行良好,但在 Windows XP 上却不行。

有问题的部分是“多播”节点,它基本上通过多播地址+端口读取和发送数据。

读取/写入网络的部分是单例。

每个访问这个单例的线程都必须指出它们何时需要开始监听,何时停止。

当至少一个线程需要“启动”时监听套接字,当所有线程“停止”时我们停止(他们必须给出一个 Guid 令牌,Start 方法返回)。

这种启动/停止机制是为了确保如果没有线程需要查看网络上发生的事情,我们不会为此消耗内存。

我遇到的问题是,在 windows XP 上,我遇到了这个异常:

System.Net.Sockets.SocketException (0x80004005): The I/O operation has been aborted because of either a thread exit or an application request
   at System.Net.Sockets.Socket.EndReceiveFrom(IAsyncResult asyncResult, EndPoint& endPoint)
   at System.Net.Sockets.UdpClient.EndReceive(IAsyncResult asyncResult, IPEndPoint& remoteEP)

经过一番搜索,在 Windows XP 及以下版本中,当线程结束时,操作系统会释放其所有 I/O 资源。 (VB.NET 3.5 SocketException on deployment but not on development machine)。

有没有办法避免这种行为?因为在我的情况下,我创建一个在执行结束之前结束的线程是很正常的,而且我不想释放它的套接字?

如果不可能,你将如何处理?

【问题讨论】:

    标签: c# .net sockets windows-xp udpclient


    【解决方案1】:

    异步操作的调用线程在操作完成之前终止。

    异步 ​​I/O 操作使用称为 IOCP(I/O Completion Port)的机制在 I/O 操作结束时通知正在执行的线程。

    幕后,整个事情基于一种称为重叠 I/O 的东西。在 Windows Vista 中,重叠 i/o 的行为发生了变化,因此当调用线程中止时,I/O 操作不再被取消。

    在 Windows Vista 之前(例如 XP),每当调用线程中止时,由该线程发起的任何重叠 i/o 都会被取消,这可能就是此异常的原因。

    您可以在此处阅读更多信息:http://www.lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html

    您无法覆盖此行为,但可以确保(例如,使用事件)您不会尝试使用创建线程不再处于活动状态的任何 I/O 资源。

    【讨论】:

    • 嗯,我想我宁愿尝试删除此启动/停止行为并在单例实例化中实例化我的套接字。因为我需要在我的单例中为所有线程提供这些套接字,即使第一个访问它的线程结束。这有意义吗?
    【解决方案2】:

    所以这似乎是由于 Windows XP 在线程结束时自动释放线程创建的资源(VB.NET 3.5 SocketException on deployment but not on development machine)。

    所以,我的解决方法是让一个线程将IsBackground 属性设置为true,即在BlockingCollection 上进行迭代。当我需要再监听一个 IP 时,我将这个 IP 添加到阻塞集合中,这个线程会创建它。

    由于该线程在整个应用程序生命周期中永远不会结束,因此不会释放资源。我已经让这种行为检查Environment.OSVersion.Version.Major 是否大于或等于 6,这是 Vista 版本号。

    现在它在所有版本上都像魅力一样工作

    【讨论】:

      【解决方案3】:

      在较新的 .NET FrameWork 版本上,这可以解决问题。

      TaskEx.Run(() => _udp.BeginReceive(AsyncCallback, state)).ConfigureAwait(false);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-02
        • 2013-09-02
        相关资源
        最近更新 更多