SO_SNDBUF的作用是什么?

9

我无法理解以下代码片段如何以及为什么能够工作:

    /* 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字节

再次问一遍,为什么?

2个回答

16
设置SO_SNDBUF选项的效果对TCP和UDP有不同的影响。
  • 对于UDP,这将设置数据报的大小限制,即超过此大小的数据将被丢弃。
  • 对于TCP,这仅仅是为给定套接字设置内核缓冲区的大小(会舍入到页面边界并有上限)。
由于你似乎在谈论TCP,所以你观察到的现象可以通过套接字处于阻塞模式来解释,因此send(2)会阻塞,直到内核能够接受所有数据,或者网络堆栈异步地将数据出队并推送到网络卡中,从而释放缓冲区中的空间。
此外,TCP是一种流协议,它不保留任何"消息"结构。一个send(2)可能对应于其他一端的多个recv(2),反之亦然。将其视为字节流。

如果套接字处于非阻塞模式,会发生什么情况? 我尝试了以下操作: 1)将缓冲区大小更改为10000会发送16384字节 2)将缓冲区大小更改为20000会发送30000字节 再次问一遍,为什么会这样? - Arun
@Arun:那只是四舍五入,为什么那很重要吗?你不应该依赖于缓冲区恰好是n个字节的事实。内核可能会分配更多的空间。 - Karoly Horvath
1
首先,内核不会按照你的缓冲区大小进行操作,正如@yi_H所指出的那样。其次,网络栈对于你的进程是异步操作的。尝试以下操作——开始向套接字写入数据,但是不要在另一端读取。最终你会得到一个短暂的响应(内核接收到比你提供的更少的字节),或者写操作失败。 - Nikolai Fetissov
TCP套接字对我来说没有任何反应。我制作了一个客户端服务器应用程序,在服务器接受连接后会无限期地休眠,而客户端则不断发送消息。缓冲区从未溢出,我的发送调用也不会阻塞,正如http://linux.die.net/man/2/send所述。 - Asna

4

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


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