首页 > 解决方案 > .NET Core 2.2 中 Socket BeginConnect 同步执行回调

问题描述

我看到了一些意想不到的行为,虽然不一定会导致问题,但我想了解有关异步套接字编程的问题。

这是关于 mySocket.BeginConnect 调用的执行及其对提供的 AsyncCallback 的调用。使用一些用于网络通信的测试项目,我看到对于相同的代码,提供的回调有时会在 BeginConnect 执行期间被同步调用,有时会被异步调用(BeginConnect 在完成回调之前已经返回 IASyncResult),后一种情况是最常见的(80% - 90% 的案例)。

但是,我无法通过一个非常简单的测试用例来重现同步回调调用,该测试用例带有套接字 tcp 客户端和服务器通信,只是垃圾邮件连接/断开调用。

我查看了 .NET Core 2.2 框架的源代码,发现底层的 LazyAsyncResult 类有两个构造函数,其中一个在其构造函数中同步调用回调。但是,我没有发现框架使用该构造函数的任何情况。我使用调试器进行的调用似乎总是创建一个 ContextAwareResult,它只有一个对另一个构造函数的基本构造函数调用。在其中一些测试用例中,我还可以在调试器中清楚地看到 CompletedSynchronously 属性返回 true。

在哪种情况下同步调用此回调的任何提示以及为什么?

干杯。

编辑:

标签: c#sockets.net-core

解决方案


您没有指定用于测试的操作系统,但假设它是 Windows 的情况(对于非 Windows,我很有信心地说行为应该相似)这是异步 I/O 操作的预期行为。特别是不能保证异步 I/O 请求总是异步完成。当 I/O 管理器可能出于明显的原因尝试缩短 I/O 操作路径时(很好的示例是快速 I/O 操作,它通过设备驱动程序绕过典型的 I/O 流并直接与内存管理器通信 - 这主要是为了可以兑现的文件操作)。在这种情况下,结果可以在同一个线程中返回,而不管操作是否被请求为异步。对于网络 I/O,这种行为最常见于读取操作(对于数据已经读入内部缓冲区的情况),而对于写入操作(对于 TCP,主要用于 Nagle 或延迟 ACK 在完成时打开的情况)输出操作不需要等待 ACK 数据包)。至于打开 TCP 连接的场景,当 TCP 握手过程省略网络层时,就像 SIO_LOOPBACK_FAST_PATH 选项的情况一样(请参阅此处此处了解更多详细信息),但只能用于环回(本地主机)接口套接字。

.NET I/O 异步建立在本机 I/O 机制之上,并继承了这些机制的属性和行为。


推荐阅读