在Linux上select缓慢的套接字

我有一个奇怪的问题,select在Linux上套接字意想不到的长。

  • 服务器一直在接收数据,接收套接字缓冲区大小为65536。
  • 一个客户端一直发送数据,发送套接字缓冲区大小为4096。

一般来说,数据传输非常快。 但是:在客户端testing一个写入是否会阻塞的时间非常长(发送数据之前没有调用select:0.5s,在发送数据之前发送数据与调用select相同:5s)。 问题是特定于缓冲区大小。 如果我增加在客户端的发送缓冲区,让我们说4 * 4096问题消失。

现在我想知道为什么select需要这么长的特定的缓冲区大小。 示例代码在这里: http : //pastebin.com/PqisLnLU

相同的代码在Windows上运行,甚至在没有这些怪异行为的Linux Windows子系统上运行。

谢谢!

您将看到Nagle算法的效果,该算法用于以延迟为代价来提高TCP吞吐量。

写入相对较小,如果在不久的将来写入更多的数据,这些写入会被延迟,然后可以将它们捆绑在一个IP数据包中。 当你在发送之前使用select ,你并没有发送更多的消息(因为发送缓冲区仍然是满的),所以在发送数据包(缓冲器被清空)之前有一个明显的延迟。 如果您不使用select则缓冲区已满,因此在send更多内容时,会立即通过网络堆栈进行分流。

(我猜你正在同一台机器上运行你的客户端和服务器程序,所以它们之间的“网络”连接实际上是回送接口,它具有相当高的MTU;否则,Nagle的算法可能不会成为问题这里)。

当你充分地增加缓冲区大小时,在填充缓冲区的某个时候,达到一个合适的IP数据包大小,并且数据立即通过网络(当收到确认后从发送缓冲区清除) – 所以没有延迟。

尝试禁用Nagle的算法(在客户端中):

 #include <netinet/tcp.h> ... value = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(int))) { printf("\n Error : SetSockOpt TCP_NODELAY Failed \n"); } 

您将会看到,使用select的变体和没有select操作的变体一样快。

我想知道为什么选择需要这么长的具体缓冲区大小

由于客户端的发送缓冲区太小。 4096字节小于我知道的任何操作系统的默认值。 Linux上的默认值比10年前大约52k左右。 除非发送方的套接字发送缓冲区大小与接收方的套接字接收缓冲区相差无几,否则不能“填满管道”。

我也会质疑你为什么要在客户端使用非阻塞I / O和select() 。 除非你连接到多台服务器,否则没有任何意义。 只要使用专用的线程,让它阻止。