C# 第二次调用NetworkStream beginhead()大规模资源争用
我正在用C# 第二次调用NetworkStream beginhead()大规模资源争用,c#,multithreading,asynchronous,tcpclient,networkstream,C#,Multithreading,Asynchronous,Tcpclient,Networkstream,我正在用TcpClient和NetworkStream对象编写服务器/客户端项目。我希望许多客户端连接到服务器,这些客户端存储在自定义网络节点对象的列表中,每个对象都有一个TcpClient和一个NetworkStream,用于与相应的客户端通信 服务器需要能够保持与客户端的连接,并在收到消息后立即(快速)等待和操作消息。对于这个应用程序来说,同步轮询是非常不可取的,我也不希望以这种方式编写它 目前,服务器正在异步接受客户机,并将其添加到列表中,工作非常顺利。我用一个控制台应用程序测试了这一点,
TcpClient
和NetworkStream
对象编写服务器/客户端项目。我希望许多客户端连接到服务器,这些客户端存储在自定义网络节点对象的列表中,每个对象都有一个TcpClient
和一个NetworkStream
,用于与相应的客户端通信
服务器需要能够保持与客户端的连接,并在收到消息后立即(快速)等待和操作消息。对于这个应用程序来说,同步轮询是非常不可取的,我也不希望以这种方式编写它
目前,服务器正在异步接受客户机,并将其添加到列表中
,工作非常顺利。我用一个控制台应用程序测试了这一点,该应用程序生成多达100个客户端,并在很短的时间内(<1秒)通过环回地址连接到服务器
将客户端添加到列表中时
对象使用GetStream()
方法返回客户端的NetworkStream
对象。我正在尝试使用NetworkStream.BeginRead()
方法实现来自每个TCP客户端的异步数据接收。对该方法的第一次调用如下所示:
this.Stream.BeginRead(readBuffer, readBufferOffset, readBuffer.Length - readBufferOffset,
new AsyncCallback(nodeStreamReadCallback), this.Stream);
由于console测试应用程序在连接到服务器后立即发送一些数据,因此对象的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()执行第二个调用,目的是等待下一个数据块到达或可用,无论将来何时
当我注释掉对Stream.BeginRead()
的第二个调用时,所有操作都非常顺利。所有数据都被接收并发送回每个客户机,没有延迟,并且线程使用量极低(在这个过程中,平均增加2到3个线程)
但是-即使只有一个单客户端连接,如果我尝试在readCallback()
方法(如上)内对Stream.BeginRead()
进行第二次调用,我也会遇到大量的争用问题。对于单个客户机,第二次调用后的CPU使用率从~0%跳到30%到60%之间,线程数可以从11跳到35
所以这是一个线程或递归问题,我觉得我应该等待一些东西,但我不能完全理解这里发生的事情。这与我使用的TcpListener.BeginAcceptTcpClient()
的模式相同,因此我认为它必须以不同的方式运行
我感谢您可能提供的所有建议,并提前感谢您的帮助 检查您的\u bytesRead
是否为0,因为这意味着您的流在远程端被关闭。在这样的流上再次调用BeginRead
会直接导致调用回调时读取字节的计数一次又一次为0。您是否检查了\u bytesRead
是否为0?因为这意味着您的流在远程端被关闭。在这样的流上再次调用BeginRead
将直接导致反复调用读取字节数为0的回调。您在哪里重置readBufferOffset
?@abto您是对的!在我的控制台测试应用程序中,我使用(NetworkStream=client.GetStream(){}通过发送数据
block。当使用块完成发送数据时,流不再可用,并在\u bytesRead
参数中返回0。检查此项可防止无限循环。谢谢!这确实是答案,请您将其移动到答案中,以便我可以将其标记为正确。您是对的!在我的控制台测试应用程序中操作I通过使用(NetworkStream=client.GetStream(){}
块发送数据。当使用块完成发送数据时,流不再可用,并在\u bytesRead
参数中返回0。检查此操作可防止循环。