【问题标题】:Setting SO_RCVBUF decreases window scaling factor设置 SO_RCVBUF 会降低窗口缩放因子
【发布时间】: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


【解决方案1】:

SYN 段的实际窗口大小不受缩放影响。例如。在您的示例中,它恰好等于 65535,而不是您计算的 8,388,480。这是因为客户端还不知道接收端是否支持窗口缩放。窗口缩放字段的作用类似于发送端支持窗口缩放的通知,并且进一步段的窗口大小必须计算为window_size<<window_scale

例子:

  1. 客户端发送 SYN,“窗口大小值”=29200,“窗口比例”=7。此时实际窗口大小为 29200。
  2. 客户端收到 ACK,SYN
  3. 客户端发送“窗口大小值”=229 的 ACK。实际窗口大小等于 229 * 2^7 = 29312。

因此,您需要查看更多部分以找出实际的窗口大小。

【讨论】:

  • 窗口缩放字段的作用类似于发送方支持窗口缩放的通知:这不是 SO_RCVBUF 设置的吗?我知道在 SYN 的那一刻,窗口大小不是我们设置的值。问题在于支持的窗口大小,而不是 SYN 时的实际窗口大小。
猜你喜欢
  • 2016-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-28
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
相关资源
最近更新 更多