我有一个奇怪的问题,选择在Linux上的套接字上取意外长。
一般来说,数据传输速度非常快。但是:客户端中的一个选择来测试写入是否会阻塞非常长(在没有调用select之前发送数据:0.5s,在实际发送数据之前使用select select发送相同的数据:5s)。问题是缓冲区大小特有的。如果我在客户端增加发送缓冲区让我们说4 * 4096问题就会消失。
现在我想知道为什么select使用特定的缓冲区大小需要这么长时间。示例代码在此处:http://pastebin.com/PqisLnLU
相同的代码在Windows甚至Windows子系统Linux上运行,没有这些奇怪的行为。
谢谢!
答案 0 :(得分:1)
我想知道为什么select使用特定的缓冲区大小
需要这么长时间
因为客户端的发送缓冲区太小。 4096字节小于我所知道的任何操作系统的默认值。 Linux上的默认值比十年前高出约52,000。你不可能填满管道。除非您的发送方套接字发送缓冲区的大小与接收方的套接字接收缓冲区相当。
我还会质疑为什么你在客户端使用非阻塞I / O和select()
。除非你连接到多个服务器,否则没有意义。只需使用专用线程并让它阻止。
答案 1 :(得分:1)
您正在看到Nagle's algorithm的效果,它用于以延迟为代价提高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
操作的变体一样快。