c# - 第二次调用 NetworkStream BeginRead() 大量资源争用

标签 c# multithreading asynchronous tcpclient networkstream

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

相关文章:

C#:同一应用程序中的 WPF 和命令行

C# Math.Sqrt() 不工作

mysql - Node.js 不等待 MySQL 服务器发送应答,继续异步工作

c# - Silverlight 和异步调用的问题

c# - 在 C# (CSV) 中将字符串转换为字节数组

c# - 如何在.NET中将一个项目编译成多个dll

c++ - 如何故意触摸内存页?

java - 多个线程不能同时工作

c++ - 使用 Boost Asio 套接字为双端队列调用移动构造函数时出现问题

php - 在 AngularJS 中使用 ngRepeat 的控制台出错