从一个线程多次调用 NetworkStream.BeginWrite 是否安全?

Is safe to call NetworkStream.BeginWrite multiple times from one thread?

我正在我的 Unity3D 游戏中实现一个 TCP 客户端,我想知道在不等到上一个调用完成写入的情况下调用 NetworkStream.BeginWrite 是否真的安全。

根据我在阅读文档时的理解,在我不在不同线程中执行并发 BeginWrite 调用之前是安全的(Unity 只有一个线程用于游戏主循环)。

对于我的阅读,我在与异步回调建立连接后立即调用 BeginRead,在异步回调中我从 TcpClient.GetStream() 读取传入数据,将其放入带有锁(readMemoryStream)的单独 MemoryStream,然后运行 再次开始阅读。除此之外,在我的 Update() 函数中(在主游戏线程中)我检查 readMemoryStream 中的新数据,检查可靠消息并将其解压缩(当然使用相同的锁(readMemoryStream))并对基于服务器消息的游戏对象。

这种方法行得通吗? BeginRead 不会干扰 BeginWrite 吗? 同样,我正在使用回调线程读取数据和主线程写入。

只要没有两个线程同时调用 BeginWrite() ,一切都很好。同一个线程,甚至其他线程,可以在较早的调用完成之前连续调用 BeginWrite()

请注意,完成回调 可能会 乱序执行;如果您确实以这种方式实现它并且完成回调的执行顺序很重要,则由您来跟踪哪个异步操作是哪个。当然,对于写入套接字,这通常并不重要,因为除了调用 EndWrite().

之外,您在完成回调中可能没有任何事情可做。

读取和写入套接字是完全独立的操作。套接字是全双工的,可以安全地处理同一套接字上并发挂起的读写操作。


您没有询问,但与 BeginWrite() 一样,您也可以多次调用 BeginRead() 而无需完成先前的操作。同样,与 BeginWrite() 一样,由您来跟踪操作的正确顺序,以便在为每个操作执行完成回调时,您知道接收到的数据应该按哪个顺序。

请注意,由于完成的顺序对于读取操作至关重要(对于写入操作通常不是这种情况),除了最大规模的实现之外,在给定套接字上永远不会重叠读取操作是很常见的。对于给定的套接字,一次只进行一个读取操作时,代码要简单得多。


最后一个警告:请注意,您的缓冲区在 I/O 操作期间是固定的。由于碎片,太多未完成的 I/O 操作会干扰堆的有效管理。这在客户端实现中不太可能成为问题,但大规模服务器实现应该考虑到这一点(例如,通过分配大缓冲区,以便它们来自 LOH,无论如何事情总是固定的)。