我正在编写一个小程序来测试网络吞吐量,作为练习的一部分,需要将发送和接收缓冲区增加到256 KB(以尝试提升TCP性能)。我使用setsockopt()
和SO_SNDBUF / SO_RCVBUF选项执行此操作,并且还增加了'net.core.rmem_max'和'net.core.wmem_max'值。
getsockopt()确认缓冲区大小的增加(256KB值的两倍)所以我知道这很好。然而,当我从一个主机向另一个主机发送256KB数据时,接收器总是在几个不同大小的读取中接收它(形成介于20到40之间的读取范围,接收字节数从1448到18824),直到它接收到所有数据。我在这一点上非常困惑,主要是这些问题,
下面是显示读取部分的接收器侧片段
while(1) {
memset(&client_addr, 0, sizeof(client_addr));
if ((connfd = accept(listenfd, (struct sockaddr*)&client_addr, &socklen)) <= 0) {
perror("accept()");
exit(EXIT_FAILURE);
}
while ((n = recv(connfd, &buff[0], BUFF_SIZE, 0/*MSG_WAITALL*/)) > 0) {
totalBytes += n;
++pktCount;
printf("Received(%d): %d bytes\n", pktCount, n);
}
if (n == 0) {
printf("Connection closed (Total: %lu bytes received)\n", totalBytes);
}
close(connfd);
connfd = -1;
totalBytes = 0;
pktCount = 0;
}
任何帮助都会很棒。
TIA
答案 0 :(得分:2)
增加缓冲区大小不应该在一次读取中接收它吗?
没有。 TCP / IP是一种流协议,可以通过较小的数据包对数据进行分段。缓冲区大小主要影响底层网络层实现可以使用多少内存(并且Linux通常会将您设置的内容加倍),但不能保证接收将以与发送方发送它的大小完全相同的块的形式接收数据(之后)所有,当你拨打send()/write()
时,并不意味着实际发送了数据包。此外,由于MTU,你最有可能将数据包拆分。
为什么每次读取的字节数差异太大(不应该更不常见)?
您可能想要调试发生这种情况的原因。有数百个因素 - 使用的NIC,其设置,驱动程序,TCP / IP,TCP,以太网网络层设置,发送器和接收器之间的东西(即交换机)等。但是,嘿,你的操作系统会有更多的数据进入并且应用程序正在处理前一个块。鉴于将数据从NIC传递到用户空间应用程序的事实相对非常昂贵,因此数据被缓冲并且您可以获得不同大小的数据并不奇怪。
有没有办法确保在一次读取中收到256KB?
可能有。有人可能会使用阻塞read()
并要求操作系统仅在收到至少256KB或发生错误时唤醒进程。
答案 1 :(得分:2)
您将有大约180个数据包要发送,这些数据并非接近大量数据。在发送和接收时,Nagle将导致任意操作系统缓冲任意数量的数据包。
通过recv()
呈现任何缓冲数据包的触发器取决于实现。在一定时间之后,或者在达到一定量的内部缓冲区大小之后,它可能很好地呈现所有分组。在某些操作系统上,您可以使用SO_RCVLOWAT
套接字选项更改这些级别。