我正在使用 TcpClient
编写服务器/客户端项目和NetworkStream
对象。我预计许多客户端会连接到服务器,这些客户端存储在 List<>
中定制NetworkNode
对象,每个对象都有一个 TcpClient
和一个 NetworkStream
用于与相应客户进行通信。
服务器需要能够保持与客户端的连接,并在收到消息后立即(快速)等待和操作消息。对于这个应用程序来说,同步轮询是非常不可取的,我也不想以这种方式编码。
当前服务器正在异步接受客户端并将它们添加到 List<>
,工作相当顺利。我已经使用控制台应用程序对此进行了测试,该应用程序生成最多 100 个客户端,并在很短的时间(< 1 秒)内连接到环回地址处的服务器。
当客户端添加到List<>
时该对象使用 GetStream()
方法返回客户端的 NetworkStream
目的。我正在尝试使用 NetworkStream.BeginRead()
方法来实现来自每个 TCP 客户端的异步数据接收。对该方法的第一次调用如下:
this.Stream.BeginRead(readBuffer, readBufferOffset, readBuffer.Length - readBufferOffset,
new AsyncCallback(nodeStreamReadCallback), this.Stream);
由于控制台测试应用程序在连接到服务器后立即发送一些数据,因此该对象的 readCallback(IAsyncResult)
方法几乎立即被调用:
private void readCallback(IAsyncResult ar)
{
NetworkStream _stream = (NetworkStream)ar.AsyncState;
int _bytesRead = 0;
_bytesRead = _stream.EndRead(ar);
this.Stream.Write(readBuffer, readBufferOffset, _bytesRead);
//increase buffer offset value
readBufferOffset += _bytesRead;
//TODO process the received data
...
//wait for the next chunk of data
this.Stream.BeginRead(readBuffer, readBufferOffset, readBuffer.Length - readBufferOffset,
new AsyncCallback(readCallback), this.Stream);
}
我正在第二次调用Stream.BeginRead()
目的是等待下一个数据 block 到达或可用,无论将来何时。
当我注释掉对 Stream.BeginRead()
的第二次调用时一切都运作得非常顺利。所有数据都会被接收并发回给每个客户端,没有延迟,并且线程使用极少(在此过程中平均使用 2 到 3 个额外线程)。
但是 - 即使只有单个客户端已连接,如果我尝试向 Stream.BeginRead()
进行第二次调用 readCallback()
内方法(如上所述) 我遇到大量争用问题。对于单个客户端,第二次调用后 CPU 使用率从 ~ 0% 跃升至 30% 到 60% 之间,线程数可以从 11 个跃升至 35 个之多。
所以这是一个线程或递归问题,我觉得我应该等待一些东西,但我不能完全理解这里发生的事情。这与我在 TcpListener.BeginAcceptTcpClient()
中使用的模式相同。所以我认为它的运作方式一定不同。
非常感谢您提供的任何建议,并提前感谢您的帮助!
最佳答案
检查您的 _bytesRead
是否为 0,因为这意味着您的流已在远程端关闭。再次在此类流上调用 BeginRead
将直接导致一次又一次地以 0 的读取字节数调用回调。
关于c# - 第二次调用 NetworkStream BeginRead() 大量资源争用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32042422/