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

我已经使用SocketAsyncEventArgs实现了这种高性能/高吞吐量的TCP服务器,经历了各种各样的麻烦,使用一个预先分配的较大的byte数组和SocketAsyncEventArgs池来接收和接收那些固定的缓冲区,并使用一些低级的东西带有一些TPL数据流和一些Rx的 Shiny 智能代码,它可以完美运行;在这方面几乎是教科书-实际上,我已经从他人的代码中学到了80%以上的这些东西。

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

  • 复杂度:我无法将对此服务器的任何修改委派给另一个
    团队成员。这使我无法完成此类任务,我可以
    对其他项目的其他部分没有给予足够的重视。
  • 内存使用情况(固定的byte数组):使用SocketAsyncEventArgs池需要
    被预先分配。因此,用于处理100000个并发连接
    (更糟糕的情况,甚至在不同的端口上)一大堆RAM毫无用处地徘徊;
    预先分配的(即使某些时候满足了这些条件,
    服务器应该每天能够处理1或2个这样的高峰)。
  • TcpListener实际上效果很好:我实际上已经对TcpListener进行了测试(有一些技巧
    在专用线程上使用AcceptTcpClient,而不使用而不是 async版本,然后将接受的连接发送到ConcurrentQueue,而不是就地创建Task等)
    并使用最新版本的.NET,效果很好,几乎一样好
    作为SocketAsyncEventArgs,没有数据丢失并且内存占用少
    这有助于避免在服务器上浪费过多的RAM,并且不需要预先分配。

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

    最佳答案

    我看不到任何证据表明这个问题与TcpListener有关。看来您只关心处理已被接受的连接的代码。这样的连接独立于监听器。
    SocketAsyncEventArgs是CPU负载优化。我相信您可以通过它获得更高的每秒操作率。与普通APM/TAP异步IO的区别有多大?当然小于一个数量级。大概在1.2倍至3倍之间。上次我对环回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只能在不从套接字读取的情况下才能增加,因此我们不会冒意外地读取太小的风险。

    另外,您可以通过分配一些非常大的缓冲区并分发块来对抗托管堆碎片。

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

    关于c# - TcpListener与SocketAsyncEventArgs,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27755330/

    10-13 03:36