理解set/getsockopt SO_SNDBUF大小加倍

48

你好,我有一个用于检查UDP套接字发送缓冲区大小的程序。然而,返回值对我来说有点混乱。我使用以下简单应用程序:

#include <sys/socket.h>
#include <stdio.h>

int main(int argc, char **argv)
{
 int sockfd, sendbuff;
 socklen_t optlen;

 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 if(sockfd == -1)
     printf("Error");

 int res = 0;

 // Get buffer size
 optlen = sizeof(sendbuff);
 res = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);

 if(res == -1)
     printf("Error getsockopt one");
 else
     printf("send buffer size = %d\n", sendbuff);

 // Set buffer size
 sendbuff = 98304;

 printf("sets the send buffer to %d\n", sendbuff);
 res = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));

 if(res == -1)
     printf("Error setsockopt");


 // Get buffer size
 optlen = sizeof(sendbuff);
 res = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);

 if(res == -1)
     printf("Error getsockopt two");
 else
     printf("send buffer size = %d\n", sendbuff);

 return 0;
}

在我的机器上输出为:

发送缓冲区大小为129024

将发送缓冲区设置为98304

新的发送缓冲区大小为196608

有人可以解释一下我做错了什么,或者如何解释这个输出吗?

1个回答

61
您没有做错任何事情。在Linux内核中,当您设置SO_SNDBUF值时,它会将其加倍,并在查询时返回加倍的值。根据man 7 socket文档所述,SO_SNDBUF选项用于设置或获取套接字的最大发送缓冲区大小(以字节为单位)。使用setsockopt()函数设置此选项时,内核会将该值加倍,以便为账务开销预留空间,并在使用getsockopt()函数进行查询时返回加倍后的值。默认值由wmem_default sysctl设置,最大允许值由wmem_max sysctl设置。此选项的最小(加倍后)值为2048。
注意:Linux假定发送/接收缓冲区的一半用于内部内核结构;因此sysctl值是可以观察到的值的两倍。

14
神圣的网络,蝙蝠侠!那就是所有skbuf的东西所在的地方 :) (注:skbuf是指Linux内核中的一个数据结构,用于管理网络数据包) - Nikolai Fetissov
1
@csyangchen: 我只能猜测,但我认为某人有一个想法,即通过将缓冲区设置为大小n,缓冲区应该能够容纳n个字节的有效负载。因此,在连接异常底层协议(例如UDP)的情况下,需要额外的缓冲区大小来容纳消息头。 - Aconcagua
@csyangchen我也想要比那个含糊的解释更多的细节。 我会猜测它可能与TCP的操作方式有关,例如,当缓冲区为XX字节时,同样大小的字节也可以向目标飞行。 在这些字节被远程ACK之前,必须将其保留在发送方侧面,在最坏的情况下,如果远程回复缓慢且TCP窗口大于SNDBUF,则可能是该缓冲区的两倍。 - Pavel P
简而言之:1983年的人们几乎没有编写API的经验,所以如果你想使用那些恐龙技术,就必须面对这样的荒谬问题。不幸的是,整个互联网都是基于这些技术构建的,因此最终必须将其抽象化(更不用说由于相同原因,在不同平台上使用时存在微妙的差异-没有理由-因此除非您使用适当的接口封装并在底层处理它们,否则它不是可移植的API)。 - Pablo Ariel
1
@PabloAriel Linux并非于1983年编写。这种加倍问题是Linux特有的胡言乱语。其他系统不会表现出这种奇怪的方式。 - jschultz410

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接