简体   繁体   English

仅在 Windows XP 上异步接收的 UdpClient 异常

[英]UdpClient Exception on async reception only on Windows XP

I've ac# code that works very well in Windows vista/seven, but not on Windows XP.我有 ac# 代码,它在 Windows vista/seven 中运行良好,但在 Windows XP 上运行不正常。

The problematic part is a "multicast" node, that basically read and send data over a multicast address+port.有问题的部分是“多播”节点,它基本上通过多播地址+端口读取和发送数据。

The part that is reading/writing to the network is a singleton.读取/写入网络的部分是单例。

Every thread that access to this singleton must indicate when they need to start to listen, and when they stop.每个访问此单例的线程都必须指示它们何时需要开始侦听以及何时停止。

Socket are listened when at least one thread need to "Start", and we stop when all thread "Stop"(they have to give a Guid token, that the Start method return).当至少一个线程需要“启动”时监听套接字,当所有线程“停止”时我们停止(它们必须给出一个 Guid 标记,即 Start 方法返回)。

This start/stop mecanism is to ensure that if no thread need to see what is happening on the network, we don't consume memory for that.这种启动/停止机制是为了确保如果没有线程需要查看网络上发生的事情,我们就不会为此消耗内存。

The problem I got is that on windows XP, I got this exception:我遇到的问题是,在 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)

After some search, it appears, that on windows XP and below, when a thread ends, the OS release all its I/O resources.经过一番搜索,发现在 Windows XP 及以下版本中,当线程结束时,操作系统会释放其所有 I/O 资源。 ( VB.NET 3.5 SocketException on deployment but not on development machine ). VB.NET 3.5 SocketException 在部署上但不在开发机器上)。

Is there a way to avoid this behavior?有没有办法避免这种行为? Because in my case, it's normal and often that I create a thread that will ends before the end of the execution, and I don't want to have its socket released?因为在我的情况下,我创建一个将在执行结束之前结束的线程是正常的,而且我不想释放它的套接字?

If it's not possible, how will you handle this?如果不可能,你将如何处理?

The calling thread, of the async operation, is terminated before the operation completes.异步操作的调用线程在操作完成之前终止。

Async I/O operation use mechanism called IOCP (I/O Completion Port) to notify the executing thread when the I/O operation ends.异步 I/O 操作使用称为 IOCP(I/O Completion Port)的机制在 I/O 操作结束时通知正在执行的线程。

Bhind the scenes, the whole thing based on something called Overlapped I/O.在幕后,整个事情基于称为重叠 I/O 的东西。 In Windows Vista the behavior of overlapped i/o was changed, so when the calling thread aborted the I/O operation is no longer cancelled.在 Windows Vista 中,重叠 I/O 的行为已更改,因此当调用线程中止时,I/O 操作不再被取消。

Prior to Windows Vista (for example, XP), whenever the calling thread aborted any overlapped i/o initiated by this thread is cancelled, and probably this is the reason for this exception.在 Windows Vista 之前(例如 XP),每当调用线程中止时,该线程启动的任何重叠 I/O 都会被取消,这可能就是此异常的原因。

You can read more about it here: http://www.lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html您可以在此处阅读更多相关信息: http : //www.lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html

You can't override this behavior, but you can make sure (using events, for example) that you won't try to use any I/O resource that the creating thread is no longer active.您无法覆盖此行为,但您可以确保(例如,使用事件)不会尝试使用创建线程不再处于活动状态的任何 I/O 资源。

So it seems this is due to windows XP that release automatically resources created by a thread when the thread ends( VB.NET 3.5 SocketException on deployment but not on development machine ).因此,这似乎是由于 Windows XP 会在线程结束时自动释放线程创建的资源( 部署时出现VB.NET 3.5 SocketException,但在开发机器上则不然)。

So, my workaround is to have a thread that has the IsBackground property set to true, that is iterating on a BlockingCollection.因此,我的解决方法是让一个线程将IsBackground属性设置为 true,即在 BlockingCollection 上进行迭代。 When I need to listen one more IP, I add this IP on the blocking collection and this thread creates it.当我需要再侦听一个 IP 时,我将这个 IP 添加到阻塞集合中,然后该线程创建它。

Since this thread never ends in the whole application life, the resources are not released.由于此线程在整个应用程序生命周期中永远不会结束,因此不会释放资源。 I've made this behavior checking the Environment.OSVersion.Version.Major to be bigger or equals to 6, which is the Vista version number.我做了这个行为检查Environment.OSVersion.Version.Major是否大于或等于 6,这是 Vista 版本号。

Now it works like a charms onall versions现在它就像所有版本的魅力一样

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM