正如 O.K.W.说,多个待定BeginSend
通话会正常进行。不过,您可能确实需要记住一些事情。
首先,如果这是一个 TCP 套接字,那么这仍然是点对点之间的单个数据流。
其次如果你所有的BeginSend
调用发生在同一线程上,那么结果将是对等方按照调用顺序接收数据。如果你的BeginSend
调用从不同的线程发生,然后数据可能以任何顺序到达,因为每个发送之间可能存在竞争条件。这对您来说可能重要,也可能无关紧要(取决于您是否在每次发送时发送离散的完整消息)。
第三,如果您使用 TCP 并且发送速度比套接字另一端的代码可以接收的速度快,那么您可能会填充 TCP 窗口,并且 TCP 堆栈将开始对数据流执行流量控制。如果继续发出BeginSend
那么您可能最终会遇到这样的情况:您的回调需要越来越长的时间来调用,因为服务器上的 TCP 堆栈将数据排队发送(只有在数据发送完毕后您才会收到回调,并且基于 TCP 窗口的流量控制将阻止发送新数据,直到 TCP 窗口不再“满”为止;即,对等方已为某些数据发送了 ACKin flight
).
然后,您可能会遇到这样的情况:您以一种无法控制的方式耗尽发送机器上的资源(您发出BeginSend
并且不知道它何时完成,并且每次发送都使用内存用于正在发送的缓冲区,并且可能non-paged pool
在 Winsock 代码中...Non-paged pool
是一个系统范围的资源,在 Vista 之前的操作系统上非常稀缺,如果出现以下情况,一些行为不良的驱动程序可能会蓝屏该框:non-paged pool
是低或耗尽。此外,您还可能将内存页面锁定到内存中,并且锁定内存页面的数量还有另一个系统范围的限制。
由于这些问题,通常最好实现您自己的协议级流量控制,这限制了BeginSend
可以在任何时间挂起的调用(也许使用协议级 ACK)或与 TCP 窗口流控制一起使用,并使用挂起发送的完成来发出新的发送,并且您可以将数据排队以在您自己的发送中发送内存,并完全控制所使用的资源以及在排队“太多”数据时要执行的操作。有关此内容的更多详细信息,请参阅我的博客文章:http://www.serverframework.com/asynchronousevents/2011/06/tcp-flow-control-and-asynchronous-writes.html http://www.serverframework.com/asynchronousevents/2011/06/tcp-flow-control-and-asynchronous-writes.html
看这个回复:当 tcp/udp 服务器发布速度快于客户端消费速度时会发生什么? https://stackoverflow.com/questions/1997691/what-happens-when-tcp-udp-server-is-publishing-faster-than-client-is-consuming/1998127#1998127有关 TCP 窗口流量控制的更多信息,以及当您忽略重叠 I/O(在 C++ 领域)并发出太多重叠发送时会发生什么情况...
总之,发布多个并发BeginSend
调用是优化 TCP 数据流的方法,但您需要确保发送的速度不会“太快”,因为一旦发送,您就会以无法控制的方式消耗资源,这对机器来说可能是致命的您的代码正在运行。所以不要允许无限数量的BeginSend
要求出色,并且最好对盒子进行概要分析,以确保您不会耗尽系统范围的资源。