【问题标题】:Effect of SO_SNDBUFSO_SNDBUF 的作用
【发布时间】:2011-11-13 19:59:39
【问题描述】:

我无法理解以下代码段的工作方式和原因:

    /* Now lets try to set the send buffer size to 5000 bytes */
    size = 5000;
    err = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,  &size, sizeof(int));
    if (err != 0) {
        printf("Unable to set send buffer size, continuing with default size\n");
    }

如果我们检查发送缓冲区的值,它确实正确设置为 5000*2 = 10000。 但是,如果我们尝试发送超过发送缓冲区大小的内容,它会发送所有内容。例如:

    n = send(sockfd, buf, 30000, 0);

    /* Lets check how much us actually sent */
    printf("No. of bytes sent is %d\n", n);

这打印出 30000。

这究竟是如何工作的?发送缓冲区大小限制为 10000 的事实没有任何影响吗?如果确实如此,究竟发生了什么?某种碎片化?

更新:如果套接字处于非阻塞模式会怎样?我尝试了以下方法:

  1. 将缓冲区大小更改为 10000 (5000*2) 会导致发送 16384 个字节
  2. 将缓冲区大小更改为 20000 (10000*2) 会导致发送 30000 个字节

再说一遍,为什么?

【问题讨论】:

    标签: c linux sockets setsockopt


    【解决方案1】:

    设置SO_SNDBUF选项的效果对于TCP和UDP是不同的。

    • 对于 UDP,这会设置数据报大小的限制,即任何更大的都将被丢弃。
    • 对于 TCP,这只是设置给定套接字的内核缓冲区的大小(对页面边界进行一些舍入和上限)。

    由于您似乎在谈论 TCP,因此您观察到的效果可以通过套接字处于 阻塞模式来解释,因此 send(2) 阻塞直到内核可以接受您的所有数据,并且/ 或网络堆栈异步出队数据并将其推送到网卡,从而释放缓冲区中的空间。

    另外,TCP 是一个流协议,它不保留任何“消息”结构。一个send(2) 可以对应另一侧的多个recv(2)s,反之亦然。将其视为字节流。

    【讨论】:

    • 如果套接字处于非阻塞模式会发生什么?我尝试了以下方法:1)将缓冲区大小更改为 10000 会导致发送 16384 个字节 2)将缓冲区大小更改为 20000 会导致发送 30000 个字节 再次,为什么?
    • @Arun:这只是四舍五入。为什么这很重要?您不应该依赖缓冲区是恰好 n 个字节的事实。内核可以分配更多。
    • 首先,正如@yi_H 指出的那样,内核不会按原样获取您的缓冲区大小。然后,网络堆栈相对于您的进程异步运行。尝试以下操作 - 开始写入套接字,但不要读取其他大小。最终你会得到一个简短的(内核接受的字节比你给它的少)或写入失败。
    • 好吧,我在 TCP 套接字中什么也没有发生。我制作了一个客户端服务器应用程序,其中服务器在接受连接后无限期休眠,客户端继续发送消息。正如linux.die.net/man/2/send 所说,缓冲区永远不会溢出我的发送调用块
    【解决方案2】:

    SO_SNDBUF 配置套接字实现在内部使用的缓冲区。如果您的套接字是非阻塞的,您只能发送配置的大小,如果您的套接字阻塞,则您的调用没有限制。

    【讨论】:

      猜你喜欢
      • 2016-09-14
      • 2015-04-25
      • 2011-05-14
      • 1970-01-01
      • 2013-04-15
      • 1970-01-01
      • 2021-07-10
      • 2011-07-15
      • 1970-01-01
      相关资源
      最近更新 更多