您能解释一下SO_SNDBUF
和SO_RECVBUF
选项的具体内容吗?
好的,由于某种原因,操作系统会缓冲输出/输入数据,但我想澄清这个主题。
他们的角色(一般)是什么?
它们是每个插槽的缓冲区吗?
传输层的缓冲区(例如TCP缓冲区)和这些缓冲区之间是否存在连接?
使用流套接字(TCP)和使用无连接套接字(UDP)时,它们是否具有不同的行为/角色?
一篇好文章也会很棒。
我用Google搜索但没有找到任何有用的信息。
答案 0 :(得分:57)
“SO_”前缀用于“套接字选项”,所以是的,这些是每个套接字缓冲区的每个套接字设置。通常有系统范围的默认值和最大值。
SO_RCVBUF
更容易理解:它是内核分配的缓冲区大小,用于保存在到达网络之间的时间内到达给定套接字的数据以及程序读取的时间。拥有这个插座。使用TCP,如果数据到达并且您没有读取它,则缓冲区将填满,并且将告知发送方减速(使用TCP窗口调整机制)。对于UDP,一旦缓冲区满了,就会丢弃新的数据包。
SO_SNDBUF
只对TCP很重要(在UDP中,无论你发送什么内容都直接发送到网络)。对于TCP,如果远程端未读取,则可以填充缓冲区(以便远程缓冲区变满,然后TCP将此事实传达给内核,并且内核停止发送数据,而是将其累积到本地缓冲区中,直到它为止填上)。或者,如果存在网络问题,它可能会填满,并且内核没有收到它发送的数据的确认。然后它将减慢在网络上发送数据的速度,直到最终输出缓冲区填满为止。如果是这样,应用程序对此套接字的未来write()
调用将阻止(如果您设置了EAGAIN
选项,则会返回O_NONBLOCK
。
这一切最好在Unix Network Programming一书中进行了描述。
答案 1 :(得分:8)
在Windows中,发送缓冲区确实在UDP中有效。如果你将数据包爆炸的速度超过网络可以传输它们的速度,那么最终你将填充套接字输出缓冲区,SendTo将失败并显示“将阻塞”。增加SO_SNDBUF将有助于此。我不得不为我正在进行的测试增加发送和接收缓冲区,以便找到我可以在Windows框和Linux框之间发送的最大数据包速率。我也可以通过检测“会阻塞”错误代码,稍微休息并重试来处理发送大小。但是增加发送缓冲区大小更简单。 Windows中的默认值是8K,在这个拥有GB的RAM的PC时代看起来不小!
答案 2 :(得分:4)
在Google上搜索“SO_RECVBUF msdn”给了我......
http://msdn.microsoft.com/en-us/library/ms740476(VS.85).aspx
使用选项表中的这些行回答你的“是每个套接字”:
SO_RCVBUF int Specifies the total per-socket buffer space reserved for receives.
SO_SNDBUF int Specifies the total per-socket buffer space reserved for sends.
稍后会详细介绍:
SO_RCVBUF和SO_SNDBUF
当Windows套接字实现支持SO_RCVBUF和 SO_SNDBUF选项,应用程序可以请求不同的缓冲区大小 (更大或更小)。对setsockopt的调用即使在 实施没有提供所要求的全部金额。一个 应用程序必须使用相同的选项调用getsockopt来检查 实际提供的缓冲区大小。
答案 3 :(得分:0)
以上回答并不能回答所有问题,尤其是有关Socket缓冲区和TCP缓冲区之间的关系。
我认为它们是不同层次的不同事物。 TCP缓冲区是Socket缓冲区的使用者。
套接字缓冲区(输入和输出)是IO缓冲区,可由系统调用从用户空间中的应用程序代码访问。 例如,使用输出缓冲区,应用程序代码可以
TCP缓冲区(发送和接收)位于仅OS可以访问的内核空间中。 例如,使用TCP发送缓冲区,TCP协议实现可以
顺便说一句,UDP协议没有缓冲区,但是UDP套接字仍然可以有IO缓冲区。
这些是我的理解,我很高兴获得任何反馈/修改/更正。
答案 4 :(得分:0)
(通常)他们的作用是什么?
您要通过套接字发送的数据被复制到套接字的发送缓冲区,因此您的代码不必等待(=阻止),直到将数据真正发送到网络为止。当发送调用成功返回时,这仅意味着该数据已被放置到发送缓冲区中,协议实现将在准备好通过网络发送该数据后立即从该缓冲区中读取数据。
请记住,来自多个进程的多个套接字可能都希望同时发送数据,但是在任何时候都只能通过网络线路发送一个数据包。在发送过程中,所有其他发送者都必须等待,一旦线路空闲,实现只能处理一个发送请求。
来自网络的数据通过协议实现被写入套接字的接收缓冲区,在那里它将等待直到您的代码从那里读取。否则,所有接收将不得不停止,直到您的代码处理了传入的数据包为止,但是当数据包到达后台并共享接口时,您的代码可能会执行其他操作,因此系统必须避免其他进程无法接收其网络只是因为您的进程拒绝处理自己的传入数据。
它们是按套接字缓存的吗?
是的。每个套接字都有自己的一组缓冲区。
传输层的缓冲区(例如TCP缓冲区)和这些缓冲区之间是否存在连接?
我不确定您所说的“ TCP缓冲区”是什么意思,但是如果您指的是TCP接收和发送窗口,答案是肯定的。
TCP会定期告知对方,您的接收缓冲区中还剩下多少空间,这样,对方将永远不会发送超出接收缓冲区容量的数据。如果您的接收缓冲区已满,则另一端将完全停止发送,直到再次有空间为止。一旦您从其中读取了一些数据,情况就会如此。
因此,如果无法按防止套接字缓冲区用尽所需的频率读取数据,则增加接收缓冲区的大小可以防止TCP连接不得不暂停发送数据。
另一方面,如果发送缓冲区已满,则套接字将不再接受代码中的任何其他数据。任何发送尝试都会阻塞或失败,并显示错误(非阻塞套接字),直到再次腾出空间为止。
并且由于TCP只能处理发送缓冲区中当前的数据,因此发送缓冲区的大小也会影响TCP的发送行为。 TCP发送策略可能取决于各种因素。其中之一是已知要发送的数据量。如果您的发送缓冲区只有2 KB,那么即使您的应用可能知道,TCP永远也不会看到超过2 KB的发送数据。如果发送缓冲区为256 KB,并且将128 KB数据放入其中,则TCP将知道它必须为此连接发送128 KB数据,这可能(并且很可能会影响)TCP使用的发送策略。 / p>
使用流套接字(TCP)和使用无连接套接字(UDP)时,它们的行为/角色是否不同?
是的。这是因为对于TCP,您发送的数据只是字节流。字节与发送的数据包之间没有关系。发送80个字节可能意味着发送一个80字节的数据包或发送每个8字节10个数据包。 TCP将自行决定。传入同样。如果接收缓冲区中有200个字节,那么您将无法知道它们是如何到达那里的,从TCP套接字读取的一定数量的字节可能已使用任意数量的数据包进行了传输。因此,尽管通过基于数据包的网络以大块方式传输数据,但TCP连接的行为类似于串行线路链接。
另一方面,UDP发送数据报。如果将80个字节放入UDP套接字的发送缓冲区中,则可以肯定地将这80个字节发送到包含80字节有效负载数据的单个UDP数据包中。数据的发送方式与将其写入发送缓冲区的方式完全相同。如果一个接一个地写入80个字节,则会发送80个数据包,每个数据包包含一个字节。如果您告诉TCP套接字发送200个字节,但发送缓冲区中只剩下100个字节的空间,则TCP将向缓冲区添加100个字节,并告知您200个字节中的100个已添加。 UDP和UDP的相同情况将阻塞或失败,并出现错误,因为所有200个字节都适合或不适合。
接收时,数据报也存储在UDP接收缓冲区中,而不是字节中。如果TCP套接字先接收80个字节的数据,然后接收200个字节的数据,则可以执行一次读取调用,一次读取所有280个字节。如果UDP套接字首先接收到一个80字节的数据报,然后接收一个200字节的数据报,并且您请求从中读取280字节,那么您将得到80字节,因为读取调用返回的所有数据都必须来自同一数据报。您不能跨数据报边界读取。还要注意,如果您请求仅读取20个字节,则会收到数据报的前20个字节,而其他60个字节将被丢弃。下次读取数据时,它将来自下一个大小为200字节的数据报。
所以有两句话的区别:TCP套接字将字节存储在套接字缓冲区中,UDP套接字将数据报存储在套接字缓冲区中。而且数据报必须完全适合缓冲区,即使缓冲区有一定的可用空间,也无法完全将套接字缓冲区中无法容纳的传入数据报丢弃。