5

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

我已经实现了这个高性能/高吞吐量的 TCP 服务器SocketAsyncEventArgs,使用一个大的预先分配的byte数组和SocketAsyncEventArgs用于接受和接收的池来处理那些固定的缓冲区,使用一些低级的东西和闪亮的智能放在一起带有一些 TPL 数据流和一些 Rx 的代码,它工作得很好;几乎是这方面的教科书——实际上我已经从别人的代码中学到了超过 80% 的这些东西。

但是也存在一些问题和担忧:

  1. 复杂性:我不能将此服务器的任何类型的修改委托给团队的其他成员。这将我限制在这类任务中,我无法对其他项目的其他部分给予足够的关注。
  2. 内存使用(固定byte数组):SocketAsyncEventArgs需要预先分配使用池。因此,为了处理 100000 个并发连接(更糟糕的情况,即使在不同的端口上),一大堆 RAM 无用地悬停在那里;预先分配(即使这些条件只是在某些时候满足,服务器应该能够每天处理 1 或 2 个这样的峰值)。
  3. TcpListener实际上效果很好:我实际上已经进行TcpListener了测试(使用了一些技巧,例如AcceptTcpClient在专用线程上使用,而不是 async 版本,然后将接受的连接发送到 a 而不是就地ConcurrentQueue创建s 等)和最新版本的 . TaskNET,它工作得非常好,几乎和 .NET 一样好SocketAsyncEventArgs,没有数据丢失和低内存占用,这有助于在服务器上不浪费太多 RAM 并且不需要预先分配。

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

4

1 回答 1

3

我没有看到任何证据表明这个问题是关于TcpListener的。您似乎只关心处理已被接受的连接的代码。这种连接独立于听者。

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

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

SocketAsyncEventArgs仅在有证据表明需要时使用。它使您的工作效率大大降低。更多潜在的错误。

这是您的套接字处理循环应如下所示的模板:

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

非常简单的代码。没有回调感谢await


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

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

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

或者,如果您认为这不是问题,则无需执行任何操作。

于 2015-01-03T13:57:46.433 回答