Hex*_*Hex 28 sockets windows network-programming
你能解释一下究竟是什么SO_SNDBUF和SO_RECVBUF选择吗?
好的,由于某种原因,操作系统会缓冲输出/输入数据,但我想澄清这个问题.
他们的角色(一般)是什么?
它们是每插槽缓冲区吗?
传输层的缓冲区(例如TCP缓冲区)和这些缓冲区之间是否存在连接?
使用流套接字(TCP)和使用无连接套接字(UDP)时,它们是否具有不同的行为/角色?
一篇好文章也会很棒.
我搜索了它,但没有找到任何有用的信息.
DS.*_*DS. 58
"SO_"前缀用于"套接字选项",所以是的,这些是每个套接字缓冲区的每个套接字设置.通常有系统范围的默认值和最大值.
SO_RCVBUF更容易理解:它是内核分配的缓冲区大小,用于保存在到达网络之间的时间内到达给定套接字的数据以及拥有此套接字的程序读取的数据.使用TCP,如果数据到达并且您没有读取它,则缓冲区将填满,并且将告知发送方减速(使用TCP窗口调整机制).对于UDP,一旦缓冲区已满,将丢弃新的数据包.
SO_SNDBUF我认为,只对TCP很重要(在UDP中,无论你发送什么都直接发送到网络).对于TCP,如果远程端未读取,则可以填充缓冲区(以便远程缓冲区变满,然后TCP将此事实传达给内核,并且内核停止发送数据,而是将其累积到本地缓冲区中,直到它为止填上).或者,如果存在网络问题,它可能会填满,并且内核没有收到它发送的数据的确认.然后它将减慢在网络上发送数据的速度,直到最终输出缓冲区填满为止.如果是这样,write()应用程序将来对此套接字的调用将阻塞(或者EAGAIN如果您设置了该O_NONBLOCK选项则返回).
这一切最好在Unix网络编程书中描述.
小智 8
在Windows中,发送缓冲区确实在UDP中有效.如果你将数据包爆炸的速度超过网络可以传输它们的速度,那么最终你将填充套接字输出缓冲区,SendTo将失败并显示"将阻塞".增加SO_SNDBUF将有助于此.我不得不增加发送和接收缓冲区的测试,我正在做的是找到我可以在Windows机箱和Linux机箱之间发送的最大数据包速率.我也可以通过检测"会阻塞"错误代码,稍微休息并重试来处理发送大小.但是增加发送缓冲区大小更简单.Windows中的默认值是8K,在这个拥有GB的RAM的PC时代看起来毫无疑问!
在Google中搜索“ SO_RECVBUF msdn”给了我...
http://msdn.microsoft.com/zh-CN/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.
Run Code Online (Sandbox Code Playgroud)
稍后会有更多详细信息:
SO_RCVBUF和SO_SNDBUF
当Windows套接字实现支持SO_RCVBUF和SO_SNDBUF选项时,应用程序可以请求不同的缓冲区大小(更大或更小)。即使实现未提供请求的全部金额,对setsockopt的调用也可能成功。应用程序必须使用相同的选项调用getsockopt来检查实际提供的缓冲区大小。
他们的角色(一般)是什么?
您想要通过套接字发送的数据被复制到套接字的发送缓冲区,因此您的代码不必等待(=阻塞)直到数据真正发送到网络。当发送调用成功返回时,这仅意味着数据已被放入发送缓冲区,一旦协议实现准备好通过网络发送该数据,就会从那里读取它。
请记住,来自多个进程的多个套接字可能都希望同时发送数据,但在任何时候都只能通过网络线路发送一个数据包。在发送过程中,所有其他发送者都必须等待,一旦线路空闲,实现只能处理一个又一个的发送请求。
从网络到达的数据由协议实现写入套接字的接收缓冲区,在那里它将等待您的代码从那里读取它。否则所有接收都必须停止,直到您的代码处理传入的数据包,但是您的代码可能会在数据包到达后台时做其他事情,并且接口是共享的,因此系统必须避免其他进程无法接收其网络数据只是因为您的进程拒绝处理自己的传入数据。
它们是每个套接字缓冲区吗?
是的。每个套接字都有自己的一组缓冲区。
传输层的缓冲区(例如 TCP 缓冲区)和这些缓冲区之间是否存在连接?
我不确定您所说的“TCP 缓冲区”是什么意思,但如果您指的是 TCP 接收和发送窗口,那么答案是肯定的。
TCP 会定期告诉另一方您的接收缓冲区中还剩下多少空间,这样另一方将永远不会发送超过您的接收缓冲区的数据。如果您的接收缓冲区已满,另一方将完全停止发送,直到再次有空间为止,只要您从中读取一些数据,就会出现这种情况。
因此,如果您不能像防止套接字缓冲区满运行所需的那样频繁地读取数据,则增加接收缓冲区大小可以防止 TCP 连接不得不暂停发送数据。
另一方面,如果发送缓冲区已满,则套接字将不再接受来自您的代码的任何数据。任何发送尝试都将阻塞或失败并显示错误(非阻塞套接字),直到再次有空间为止。
由于 TCP 只能处理当前在发送缓冲区中的数据,因此发送缓冲区的大小也会影响 TCP 的发送行为。TCP 发送策略可能取决于各种因素。其中之一是已知要发送的数据量。如果您的发送缓冲区只有 2 KB,那么 TCP 将永远不会看到超过 2 KB 的发送缓冲区,即使您的应用程序可能知道会有更多的数据跟随。如果您的发送缓冲区为 256 KB,并且您将 128 KB 的数据放入其中,则 TCP 将知道它必须为此连接发送 128 KB 的数据,这可能(并且很可能会)影响 TCP 使用的发送策略。
在使用流套接字 (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套接字将数据报存储在套接字缓冲区中。并且数据报必须完全适合缓冲区,无法完全放入套接字缓冲区的传入数据报将被静默丢弃,即使缓冲区有一些可用空间。