socket编程有什么好的缓冲区大小?

uri*_*ium 31 .net sockets

我们正在使用.Net和套接字.服务器使用Socket.Sender(bytes [])方法,因此它只发送整个有效负载.另一方面,我们是消费数据的客户.Socket.Receive(缓冲液[]).在Microsoft(和其他人)的所有示例中,他们似乎都坚持使用8192的缓冲区大小.我们已经使用了这个大小,但我们偶尔会向超出此缓冲区大小的客户端发送数据.

有没有办法确定服务器发送方法发送给我们的数据量?什么是最好的缓冲区大小?

Jon*_*eet 40

即使您发送的数据多于此数据,也可能无法在一次调用Receive中使用.

您无法确定服务器发送了多少数据 - 它是一个数据,您只是一次只读取数据块.您可以阅读服务器在一个发送呼叫中发送的部分内容,或者您​​可以从一个接收呼叫中的两个发送呼叫中读取数据.8K是一个合理的缓冲区大小 - 不是那么大,你会浪费大量的内存,而不是那么小,你将不得不使用大量浪费的接收调用.4K或16K很可能也很好......我个人不会开始超过16K的网络缓冲区 - 我怀疑你很少填充它们.

您可以通过尝试使用一个非常大的缓冲区并记录每次调用接收到多少字节来进行实验 - 这可以让您了解通常可用的数量 - 但它不会真正显示使用较小缓冲区的效果.您对使用8K缓冲区有什么顾虑?如果它的性能,您是否有任何证据表明您的代码的这一方面是性能瓶颈?

  • @uriDium:您应该编写代码,以便它不依赖于从一个Receive中的单个Send中接收所有内容.这不是TCP使用的模型 - 它是*stream*模型.如果要将该流分段为不同的消息,则应使用分隔符或为每条消息写入长度前缀,以便客户端知道要读取多少内容. (6认同)

ant*_*duh 20

不幸的是,Jon Skeet的答案留下了很大一部分图片 - 发送缓冲区大小,以及您正在写入的管道的带宽延迟产品.

如果您尝试使用单个套接字通过大型管道发送数据,并且您希望TCP填充该管道,则需要使用等于管道的带宽延迟乘积的发送缓冲区大小.否则,TCP将不会填充管道,因为它不会始终留下足够的"飞行中的字节".

考虑速度为1千兆位的连接,平均单向延迟为10毫秒.往返时间(也就是说,套接字发送数据包之间经过的时间和接收该数据包的确认时间因此知道发送更多数据的时间)通常是延迟的两倍.

因此,如果您拥有1千兆位连接,并且RTT为20毫秒,那么如果完全使用该管道,则该管道始终具有1千兆位/秒*20毫秒== 2.5兆字节的数据.

如果您的TCP发送缓冲区小于2.5兆字节,那么一个套接字永远不会完全利用管道 - 您永远不会从套接字中获得千兆位/秒的性能.

如果您的应用程序使用多个套接字,则所有TCP发送缓冲区的聚合大小必须为2.5 MB,以便充分利用此假设的1千兆位/ 20毫秒RTT管道.例如,如果使用8192字节的缓冲区,则需要306个同时使用的TCP套接字来填充该管道.

  • 感谢您的解释。因此,合适的缓冲区大小在 8Ko 到 2.5 MB 之间。;-) (2认同)
  • 应该注意的是,这实际上仅适用于 TCP 套接字,因为在此,另一端将仅发送与接收者套接字缓冲区相符的数据,然后再暂停数据流并等待 ACK 到达。在 UDP 的情况下,重要的是代码永远不会让套接字缓冲区空运行,然后您还将利用任何可用的线路速度。当然,如果缓冲区更大,您可以提前生成更多数据,因此时序就不那么重要了。 (2认同)
  • @kuchi - 我为你写了一些编辑来展示数学。干杯! (2认同)

Jus*_*ier 9

这取决于您的协议.如果您期望超过8192字节的消息,则应相应地增加缓冲区大小.但请记住,此缓冲区大小仅适用于一次调用Receive.如果您真的需要/需要,可以Receive多次循环并将接收的数据复制到任意大的数据结构或缓冲区中.

另请注意,Receive在您确认已阅读给定消息的所有数据之前,最好重复调用; 即使单个消息小于缓冲区大小,单个Receive调用仍然可能无法检索到所有消息.