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

标签 c# unity3d mono tcpclient

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

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

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

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

最佳答案

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

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

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


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

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


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

关于c# - 从一个线程多次调用 NetworkStream.BeginWrite 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30636447/

相关文章:

c# - 删除 C# Chart 中的网格线并制作更粗的图形线

c# - 创建未知类型的实例

c# - 为什么不能将迭代器 block 与 IOrderedEnumerable 一起使用

c# - C# 是否有一种简单的方法来替换多个 if 语句?

c# - 任务循环退出的 CancellationTokenSource 和退出标志之间的区别

c# - 找到 Canvas 的左上角位置

c# - 统一如何使用单个操纵杆控制相机 View ?

c# - 如何在unity中动画回到第一个位置?

适用于 Windows/Linux 的 MONO 3.2 - 缺少?

c# - 自升级到 Visual Studio 2017 15.3.0 后,应用程序中出现奇怪的调试输出