【发布时间】:2016-02-10 08:20:31
【问题描述】:
我有一个用 C++ 编写的小型 Android 应用程序,它打开一个 TCP 套接字到我的 HTTP 服务器 (python -m SimpleHTTPServer) 并发送一个标头。无需进一步配置,这是设备发送的 SYN:
Transmission Control Protocol, Src Port: 47262 (47262), Dst Port: 8000 (8000), Seq: 0, Len: 0
Source Port: 47262
Destination Port: 8000
[Stream index: 47]
[TCP Segment Len: 0]
Sequence number: 0 (relative sequence number)
Acknowledgment number: 0
Header Length: 40 bytes
Flags: 0x002 (SYN)
Window size value: 65535
[Calculated window size: 65535]
Checksum: 0x54cb [validation disabled]
Urgent pointer: 0
Options: (20 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale
Maximum segment size: 1460 bytes
TCP SACK Permitted Option: True
Timestamps: TSval 3637366, TSecr 0
No-Operation (NOP)
Window scale: 7 (multiply by 128)
窗口大小为 65,535,窗口比例因子为 7,因此客户端隐含地说其接收缓冲区为 65,535 * 2 ^ 7 = 8,388,480。
现在,我在代码中添加以下几行:
unsigned long receive_buffer_size = 65535*127;
res = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &receive_buffer_size, sizeof(receive_buffer_size));
这些行出现在使用socket() 打开套接字之后,但在使用connect() 将其连接到端口之前。
我认为这不会影响接收缓冲区,因为我们提供的值与默认设置的值相同。但是,结果如下:
Transmission Control Protocol, Src Port: 47263 (47263), Dst Port: 8000 (8000), Seq: 0, Len: 0
Source Port: 47263
Destination Port: 8000
[Stream index: 2]
[TCP Segment Len: 0]
Sequence number: 0 (relative sequence number)
Acknowledgment number: 0
Header Length: 40 bytes
Flags: 0x002 (SYN)
Window size value: 65535
[Calculated window size: 65535]
Checksum: 0xcf44 [validation disabled]
Urgent pointer: 0
Options: (20 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale
Maximum segment size: 1460 bytes
TCP SACK Permitted Option: True
Timestamps: TSval 3698768, TSecr 0
No-Operation (NOP)
Window scale: 5 (multiply by 32)
接收缓冲区已减少到 65,535 * 2 ^ 5 = 2,097,120。这该如何解释?
在设置参数之前和之后,我使用以下行编写 SO_RCVBUF:
res = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &curr_value, &optlen);
在设置参数之前,SO_RCVBUF 为 1,048,576 - 与我们在第一个 snif 中看到的默认值相去甚远。之后,它是 2,097,152,这不是我使用 setsockopt() 提供的。最后一个数字与我们在第二个嗅探中看到的数量级相同,因此至少有一些一致性。
请注意,对于每个调用,res 都是肯定的,因此 getsockopt() 和 setsockopt() 始终成功。
我可以理解操作系统对设置 SO_RCVBUF 有限制,但为什么它低于默认值?为什么在设置任何值之前读取 SO_RCVBUF 会导致值低于默认值?
【问题讨论】:
-
用于设置默认值的值通常不是默认值。某些平台将您提供的值加倍。其他人则以各种方式向上或向下调整。我建议您在设置缓冲区大小后获取,看看系统真正给了您什么。
-
@EJP 设置后,缓冲区大小为 2,097,152,与我们在 snifs 中看到的值差不多。因此,我们是否可以假设该平台在 TCP 级别上的价值与我们在程序中获得的价值相比没有翻倍?
-
/proc/sys/net/core/rmem_max和/proc/sys/net/core/rmem_default的值是什么? -
它们分别是 1048576 和 229376。我不知道如何从中得出任何结论:
rmem_max正是我在更改参数之前从getsockopt()获得的数字,但是嗅探器再次表明当时最大缓冲区大小更大。而且,在setsockopt()之后,是最大值的两倍。 -
@Aegonis,还有一个问题:
getsockopt()在你调用connect()之后返回的值是多少?
标签: c++ sockets networking tcp