C# 异步.NET套接字和使用select()的标准套接字:为什么select()会阻止异步回调的发生?

C# 异步.NET套接字和使用select()的标准套接字:为什么select()会阻止异步回调的发生?,c#,.net,winapi,c++-cli,winsock,C#,.net,Winapi,C++ Cli,Winsock,我有一个用C++/CLI编写的应用程序,它使用一个用C编写的库。该应用程序使用标准套接字API编写,并使用select多路复用一组普通的非异步套接字。但是,第三方库使用.NET套接字并使用异步结果和回调 下面是一个场景:我在主线程中创建了一组常规套接字,这是一个主要使用本机风格代码的C++/CLI应用程序。我创建了第三方库供应商的C会话对象,该对象在内部具有一组来自.NET类的异步套接字 我注意到,如果我在实例化C会话对象的主线程中的select中放入一个NULL timeout参数,则根本不会

我有一个用C++/CLI编写的应用程序,它使用一个用C编写的库。该应用程序使用标准套接字API编写,并使用select多路复用一组普通的非异步套接字。但是,第三方库使用.NET套接字并使用异步结果和回调

下面是一个场景:我在主线程中创建了一组常规套接字,这是一个主要使用本机风格代码的C++/CLI应用程序。我创建了第三方库供应商的C会话对象,该对象在内部具有一组来自.NET类的异步套接字

我注意到,如果我在实例化C会话对象的主线程中的select中放入一个NULL timeout参数,则根本不会对其.NET套接字进行异步回调。如果我使用了一个超时,比如说1秒,并且在我的非异步套接字上没有其他活动发生,那么在select超时之前不会传递异步套接字回调

不知何故,select阻止了.NET套接字的回调。我如何避免这种情况?对于旧套接字,是否有其他轮询方法可供使用,以使.NET套接字仍能进行异步回调?

我找到了解决方案

在.NET中使用的异步回调中,您不能有任何阻塞的函数,包括send/recv函数,即使根据我自己的测试,它们是非阻塞的[1]。在异步回调中调用阻塞函数时,行为未定义。一旦我从代码中消除了这种不确定性,事情就开始正常工作了

我通过编写一些策略类来重新模板化我的类,这些策略类将select替换为WaitForMultipleObjectsEx,并通过在AsyncCallback中放置一个SetEvent来触发多路复用来解决这个问题。这似乎解决了大部分问题

[1] 编辑:见下面的评论。无论我是使用非阻塞套接字还是阻塞套接字发送,在破坏东西和进入未定义行为方面似乎没有什么区别。

我找到了解决方案

在.NET中使用的异步回调中,您不能有任何阻塞的函数,包括send/recv函数,即使根据我自己的测试,它们是非阻塞的[1]。在异步回调中调用阻塞函数时,行为未定义。一旦我从代码中消除了这种不确定性,事情就开始正常工作了

我通过编写一些策略类来重新模板化我的类,这些策略类将select替换为WaitForMultipleObjectsEx,并通过在AsyncCallback中放置一个SetEvent来触发多路复用来解决这个问题。这似乎解决了大部分问题


[1] 编辑:见下面的评论。无论我是使用非阻塞套接字还是阻塞套接字发送,似乎都不会对破坏内容和进入未定义行为产生影响。

我想象回调发生在同一个线程上,因此,如果Select阻塞该线程,它将无法处理运行循环中的任何其他内容。我发现令人困惑的是,Select的MSDN帮助说明,当它阻塞时,它处于可警报的等待状态。.NET异步回调不算作会引起警报的东西吗?我相信所有的.NET回调都是在应用程序中处理的;这是一个控制台应用程序。您链接的此函数似乎位于表单命名空间中。我认为回调发生在同一个线程上,因此如果Select阻止该线程,则无法处理运行循环中的任何其他内容。我发现令人困惑的是,Select的MSDN帮助说明,当它阻止时,它处于可警报的等待状态。.NET异步回调不算作会引起警报的东西吗?我相信所有的.NET回调都是在应用程序中处理的;这是一个控制台应用程序。您链接的这个函数似乎位于表单名称空间中。哦,我的意思是,如果您使send/recv成为非阻塞函数并在异步回调中使用它们,它仍然有效。当我在异步回调中切断非阻塞套接字上的发送时,事情开始工作了。切换send中使用的套接字的阻塞/非阻塞状态似乎没有什么区别。编辑了上面的响应。哦,我想说的是,如果您使send/recv成为非阻塞的,并在异步回调中使用它们,它仍然有效。当我在异步回调中切断非阻塞套接字上的发送时,事情开始工作了。切换send中使用的套接字的阻塞/非阻塞状态似乎没有什么区别。编辑了上述回复。