c# – TcpListener vs SocketAsyncEventArgs

是否有正当理由不使用TcpListener来实现高性能/高吞吐量TCP服务器而不是SocketAsyncEventArgs?

我已经使用SocketAsyncEventArgs实现了这个高性能/高吞吐量的TCP服务器,经历了各种令人头疼的问题,使用一个大的预分配字节数组处理这些固定缓冲区,并使用SocketAsyncEventArgs池进行接受和接收,使用一些低级别的东西放在一起和闪亮的智能代码与一些TPL数据流和一些Rx,它的工作完美;在这项努力中几乎是教科书 – 实际上我从其他人的代码中学到了80%以上的这些东西.

但是有一些问题和顾虑:

>复杂性:我不能将对此服务器的任何修改委托给另一个
团队成员.这限制了我这种任务,我可以
没有足够重视其他项目的其他部分.
>内存使用(固定字节数组):使用SocketAsyncEventArgs需要池
预先分配.因此,用于处理100000个并发连接
(更糟糕的是,甚至在不同的端口上)一大堆RAM无用地悬停在那里;
预先分配(即使在某些时候满足这些条件,
服务器应该能够每天处理1或2个这样的峰值).
> TcpListener实际上运行良好:我实际上已经将TcpListener放入测试中(有些技巧就像
在专用线程上使用AcceptTcpClient,而不是异步
版本,然后将接受的连接发送到
ConcurrentQueue而不是就地创建任务等)
并且使用最新版本的.NET,它运行得非常好,几乎一样好
作为SocketAsyncEventArgs,没有数据丢失和低内存占用
这有助于不在服务器上浪费太多RAM,也不需要预先分配.

那么为什么我没有看到TcpListener在任何地方被使用而且每个人(包括我自己)都在使用SocketAsyncEventArgs?我错过了什么吗?

最佳答案 我没有看到任何证据表明这个问题与TcpListener有关.您似乎只关心处理已经被接受的连接的代码.这种连接独立于听众.

SocketAsyncEventArgs是CPU负载优化.我相信你可以用它来实现更高的每秒操作速度.与普通APM / TAP异步IO的区别有多大?当然不到一个数量级.可能介于1.2x和3x之间.上次我对回送TCP事务率进行基准测试时发现内核占用了大约一半的CPU使用率.这意味着您的应用程序可以通过无限优化获得最多2倍的速度.

请记住,当CPU的功能远远不够时,SocketAsyncEventArgs在2000年左右被添加到BCL中.

仅在有证据表明需要时才使用SocketAsyncEventArgs.它会使你的工作效率低得多.更容易出错.

这是套接字处理循环应该是这样的模板:

while (ConnectionEstablished()) {
 var someData = await ReadFromSocketAsync(socket);
 await ProcessDataAsync(someData);
}

非常简单的代码.由于等待没有回调.

如果您担心托管堆碎片:在启动时分配新字节[1024 * 1024].当你想从套接字读取时,将一个字节读入该缓冲区的一些空闲部分.当单字节读取完成时,您会询问实际存在多少字节(Socket.Available)并同步拉出其余字节.这样你只需要固定一个相当小的缓冲区,并且仍然可以使用异步IO来等待数据到达.

此技术不需要轮询.由于Socket.Available只能在不读取套接字的情况下增加,因此我们不会有意外执行读取太小的风险.

或者,您可以通过分配几个非常大的缓冲区并分发块来对抗托管堆碎片.

或者,如果您没有发现这是一个问题,您不需要做任何事情.

点赞