SO_SNDLOWAT套接字选项的目的是什么?

8
我正在将一个C语言软件从Tru64移植到Linux Suse 11。在Tru64上,他们将SO_SNDLOWAT套接字选项的值设置为1024 * 64。在Linux上,此选项不可更改,其值为1。
我想知道,在Linux上不将SO_SNDLOWAT设置为1024 * 64会对软件执行产生什么影响。
问题是我找到了两个定义(解释)SO_SNDLOWAT的目的:
1. 在Linux套接字手册中找到: SO_SNDLOWAT指定缓冲区中的最小字节数,直到套接字层将数据传递给协议
我理解它指定了要进行处理的缓冲区的最小字节数(在这种情况下,用于发送消息)。缓冲区至少需要填充SO_SNDLOWAT字节才能继续进行。
2. 在书《UNIX网络编程:W. Richard Stevens、Bill Fenner、Andrew M. Rudoff的套接字网络API》中找到: 发送低水位标记是必须在套接字发送缓冲区中存在的可用空间量,以使选择返回“可写”。
我理解,如果我想在套接字缓冲区中写入(无论我要写入的大小),缓冲区至少需要有SO_SNDLOWAT字节的可用空间。
我不知道SO_SNDLOWAT的含义。
3个回答

3
正如您可以在这个问题中看到的,它涵盖了其他套接字选项,答案取决于操作系统,因此两个答案都可能是正确的,因为一个来自Linux世界,另一个来自UNIX(BSD和Co)世界。
在BSD和BSD克隆中,此选项意味着以下内容:
  1. 如果套接字是非阻塞的,并且调用send(),它必须能够一次性接受所有提供的数据或接受至少SO_SNDLOWAT字节的数据;如果不可能,则不接受任何数据,send()将失败并出错。

    因此,如果设置SO_SNDLOWAT为100并尝试发送50个字节,则会发送50个字节或什么也不发送。如果将SO_SNDLOWAT设置为100并尝试发送200个字节,则必须至少接受100个字节的数据,它可以接受更多,最多可接受全部200个字节,以及100到200之间的任何值,但不能少于100。请记住,默认值为SO_SNDLOWAT为1,这也是非阻塞套接字的默认行为(它必须接受至少1个字节或以EWOULDBLOCK失败)

    请注意,UDP套接字始终是全部或无的,它们永远不会仅接受“部分数据”,因此设置SO_SNDLOWAT仅与可能只接受所提供数据的TCP套接字相关。

  2. 如果套接字是阻塞的,则设置SO_SNDLOWATsend()调用没有实际影响,因为在这种情况下,套接字将始终接受所有数据,或者它将阻塞,然后它将阻塞直到所有数据都被接受或发送超时(如果使用SO_SNDTIMEO设置了发送超时,或底层协议具有自己的发送超时)。

  3. 无论套接字是否阻塞,无论它是UDP还是TCP,poll()select()调用仅在可以通过send()调用接受至少SO_SNDLOWAT字节时才声明此套接字可写。

那这个选项真正好在哪里呢?通常用于避免当套接字缓冲区满时,进程以每字节的方式提供数据,而是采用更大块的默认操作行为。即使在套接字缓冲区中只有一个字节的空间时,select()poll()也会表示套接字可写。换句话说,这只是一种性能优化,如果代码能正确地处理任意套接字写入,则无论是否设置SO_SNDLOWAT,以及设置到哪个值,都将能正确工作,只是在某些极端情况下,如果SO_SNDLOWAT具有合理的值,可能需要更少的CPU时间。但是,和所有性能调整一样,如果您不知道自己在做什么,通过设置错误的值很容易使事情变得更糟,所以如果有疑问,请不要触碰该设置。

1

第一个描述是正确的解释。

至于无法设置SO_SNDLOWAT的影响,我认为这并不重要,因为性能取决于像Nagle算法、路径MTU发现等因素。我怀疑其他TCP/IP实现会默默地忽略此选项。


在“链表”情况下,拥有第二个功能也是有意义的:如果select询问一个套接字是否可写,内核应该在此时分配一个缓冲区,并且只有在它能够完成时才返回给应用程序。我可以理解要求保证send至少能够接受n字节的优点。 - Simon Richter

1

据我所知,第二个是正确的,但我从未能够使用它。

SO_SNDLOWAT 在Linux上是不可更改的。 setsockopt 失败并出现错误 ENOPROTOOPT


TCP_NOTSENT_LOWAT已经在2.12内核中引入。 - hookenz
@Matt,你把TCP_NOTSENT_LOWATSO_SNDLOWAT搞混了。 - SaveTheRbtz

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