是否有正当理由不使用TcpListener
来实现高性能/高吞吐量TCP
服务器而不是SocketAsyncEventArgs
?
我已经使用SocketAsyncEventArgs
实现了这个高性能/高吞吐量的TCP服务器,经历了各种令人头疼的问题,使用一个大的预分配byte
数组和{{{}池来处理这些固定缓冲区1}}用于接受和接收,使用一些低级别的东西和闪亮的智能代码与一些TPL数据流和一些Rx放在一起,它完美地工作;在这项努力中几乎是教科书 - 实际上我从其他人的代码中学到了80%以上的东西。
然而,存在一些问题和担忧:
SocketAsyncEventArgs
阵列):使用byte
需要池
预先分配。因此,用于处理100000个并发连接
(更糟糕的是,甚至在不同的端口上)一大堆RAM无用地悬停在那里;
预先分配(即使在某些时候满足这些条件,
服务器应该每天能够处理1个或2个这样的峰值。SocketAsyncEventArgs
实际效果很好:我实际上已经对TcpListener
进行了测试(有些技巧就像
在专用主题上使用TcpListener
,不是 AcceptTcpClient
版本,然后将接受的连接发送到
async
并且没有就地创建ConcurrentQueue
等等)
并且使用最新版本的.NET,它运行得非常好,几乎一样好
如Task
,没有数据丢失和内存占用率低
这有助于不在服务器上浪费太多RAM,也不需要预先分配。那么为什么我看不到SocketAsyncEventArgs
在任何地方被使用而且每个人(包括我自己)都在使用TcpListener
?我错过了什么吗?
答案 0 :(得分:2)
我认为没有证据表明这个问题与TcpListener
完全相同。您似乎只关心处理已经被接受的连接的代码。这种联系独立于听众。
SocketAsyncEventArgs
是CPU负载优化。我相信你可以用它来实现更高的每秒操作速度。与普通APM / TAP异步IO的区别有多大?当然不到一个数量级。可能介于1.2x和3x之间。上次我对回送TCP事务率进行基准测试时发现内核占用了大约一半的CPU使用率。这意味着您的应用程序可以通过无限优化获得最多2倍的速度。
请记住,在2000年左右,当CPU的能力差得多时,SocketAsyncEventArgs
被添加到BCL中。
仅在您有证据表明需要时才使用SocketAsyncEventArgs
。它会使你的工作效率低得多。更容易出错。
这是套接字处理循环应该是这样的模板:
while (ConnectionEstablished()) {
var someData = await ReadFromSocketAsync(socket);
await ProcessDataAsync(someData);
}
非常简单的代码。 await
没有回调。
如果您担心托管堆碎片:在启动时分配new byte[1024 * 1024]
。当你想从套接字读取时,将一个字节读入该缓冲区的一些空闲部分。当单字节读取完成时,您会询问实际存在多少字节(Socket.Available
)并同步拉出其余字节。这样你只需要固定一个相当小的缓冲区,并且仍然可以使用异步IO来等待数据到达。
此技术不需要轮询。由于Socket.Available
只能在不读取套接字的情况下增加,因此我们不会有意外执行读取太小的风险。
或者,您可以通过分配几个非常大的缓冲区并分发块来对抗托管堆碎片。
或者,如果你没有发现这是一个问题,你不需要做任何事情。