设置SO_RCVBUF会降低窗口缩放系数

时间:2016-02-10 08:20:32

标签: c++ sockets networking tcp

我有一个用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()提供的。最后一个数字与我们在第二个snif中看到的数量级相同,所以至少在那里有一些一致性。

请注意,对于每次通话,res均为正,因此getsockopt()setsockopt()始终成功。

我可以理解操作系统维持设置SO_RCVBUF的限制,但为什么它低于默认值?为什么在设置任何值之前读取SO_RCVBUF会导致值低于默认值?

1 个答案:

答案 0 :(得分:3)

SYN段的实际窗口大小不适用于缩放。例如。它等于你的例子中的65535,而不是你计算的8,388,480。这是因为客户端还不知道接收方是否支持窗口缩放。窗口缩放字段的作用类似于发送方支持窗口缩放的通知,并且其他段的窗口大小必须计算为window_size<<window_scale

示例:

  1. 客户端发送SYN,其中“窗口大小值”= 29200,“窗口比例”= 7。此时实际窗口大小为29200。
  2. 客户端收到ACK,SYN
  3. 客户端发送“窗口大小值”= 229的ACK。实际窗口大小等于229 * 2 ^ 7 = 29312。
  4. 因此,您需要查看更多细分以找出实际的窗口大小。