Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# TcpListener与SocketAsyncEventArgs_C#_Sockets_Tcplistener_Tcpserver_Socketasynceventargs - Fatal编程技术网

C# TcpListener与SocketAsyncEventArgs

C# TcpListener与SocketAsyncEventArgs,c#,sockets,tcplistener,tcpserver,socketasynceventargs,C#,Sockets,Tcplistener,Tcpserver,Socketasynceventargs,是否有正当理由不使用TcpListener来实现高性能/高吞吐量TCP服务器而不是SocketAsyncEventArgs 我已经使用SocketAsyncEventArgs实现了这个高性能/高吞吐量TCP服务器,使用一个大的预分配byte数组和SocketAsyncEventArgs池来接受和接收这些固定缓冲区,经历了各种各样的麻烦,将一些低级的东西和闪亮的智能代码与一些TPL数据流和一些Rx结合在一起,它可以完美地工作;在这项工作中,我几乎是一本教科书——事实上,我从别人的代码中学到了80%

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


我已经使用
SocketAsyncEventArgs
实现了这个高性能/高吞吐量TCP服务器,使用一个大的预分配
byte
数组和
SocketAsyncEventArgs
池来接受和接收这些固定缓冲区,经历了各种各样的麻烦,将一些低级的东西和闪亮的智能代码与一些TPL数据流和一些Rx结合在一起,它可以完美地工作;在这项工作中,我几乎是一本教科书——事实上,我从别人的代码中学到了80%以上的东西

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

  • 复杂性:我无法将此服务器的任何修改委托给其他服务器 团队成员。这就把我限制在这类任务上,我可以 对其他项目的其他部分关注不够

  • 内存使用量(固定的
    字节
    数组):使用
    SocketAsyncEventArgs
    池需要 必须预先分配。所以对于处理100000个并发连接来说 (更糟糕的情况,即使在不同的港口)一大堆RAM无用地悬浮在那里; 预分配(即使在某些时候满足这些条件, 服务器应该能够每天处理1到2个这样的峰值)
  • TcpListener
    实际上效果很好
    :我实际上已经对
    TcpListener
    进行了测试(使用了一些技巧,如 在专用线程上使用
    acceptcpclient
    ,而不使用
    async
    版本,然后将接受的连接发送到
    ConcurrentQueue
    和不创建任务等) 对于最新版本的.NET,它运行得非常好,几乎一样好
    作为
    SocketAsyncEventArgs
    ,没有数据丢失和内存不足 这有助于避免在服务器上浪费太多RAM,并且无需预先分配

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

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


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


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


    只有在有证据表明需要时才使用
    SocketAsyncEventArgs
    。这会使你的工作效率大大降低。更多潜在的bug

    以下是套接字处理循环的模板:

    while (ConnectionEstablished()) {
     var someData = await ReadFromSocketAsync(socket);
     await ProcessDataAsync(someData);
    }
    
    非常简单的代码。由于
    等待
    ,因此没有回调


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

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

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


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

    @usr谢谢,你是对的,正如我在第3点提到的。我完全按照你说的做!接受是在一个简单的循环中发生的,在一个专用的
    线程上(使用
    TaskCreationOptions.longlunning
    选项创建的
    Task
    )。然后我不明白你为什么建议在SocketAsyncEventArgs和TcpListener之间进行选择。为什么不两者都用呢?一旦连接被接受,侦听器就停止播放。在我看来,这与处理连接无关。
    SocketAsyncEventArgs
    导致
    byte
    数组的缓冲区被固定,因此无法有效地进行垃圾收集,并导致内存碎片,从而导致更高的CPU和RAM使用率;加上准备和管理
    SocketAsyncEventArgs
    对象池需要克服的所有额外障碍;总而言之,它需要更多的额外工作和维护,更重要的是,这种知识/经验不容易/安全/可靠地转移给其他开发人员?以什么方式?您似乎在问:“我可以简单地用通常的APM/TAP异步IO替换SocketAsyncEventArgs吗?”这与TcpListener没有任何关系。正如我所描述的,
    TcpListener
    提供了一个简单得多的编程模型以及与
    SocketAsyncEventArgs
    相同的性能特征。但是在我研究过的所有项目中(比如fracture(F#)、SocketAwaitable、SuperSocket和许多其他示例以及这里和那里的博客文章),我找不到任何人使用
    TcpListener
    。现在我问,为什么?在你得到使用建议之前,我100%支持你