我正在我的 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/