.net 套接字编程的合适缓冲区大小是多少?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2811006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 14:16:31  来源:igfitidea点击:

What is a good buffer size for socket programming?

.netsockets

提问by uriDium

We are using .Net and sockets. The server is using the Socket.Sender(bytes[])method so it just sends the entire payload. On the other side we are clients consuming the data. Socket.Receive(buffer[]). In all the examples from Microsoft (and others) they seem to stick with a buffer size of 8192. We have used this size but every now and then we are sending data down to the clients that exceeds this buffer size.

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

Is there a way of determining how much data the server's sent method sent us? What is the best buffer size?

有没有办法确定服务器的发送方法向我们发送了多少数据?最佳缓冲区大小是多少?

回答by Jon Skeet

Even if you're sending more data than that, it may well not be available in one call to Receive.

即使您发送的数据比这更多,它也可能无法在一次 Receive 调用中使用。

You can't determine how much data the server has sent - it's a streamof data, and you're just reading chunks at a time. You may read partof what the server sent in one Send call, or you may read the data from two Send calls in one Receive call. 8K is a reasonable buffer size - not so big that you'll waste a lot of memory, and not so small that you'll have to use loads of wasted Receive calls. 4K or 16K would quite possibly be fine too... I personally wouldn't start going above 16K for network buffers - I suspect you'd rarely fill them.

您无法确定服务器发送了多少数据——它是一个数据,而您只是一次读取数据块。您可以在一次 Send 调用中读取服务器发送的部分内容,或者可以在一次 Receive 调用中读取来自两次 Send 调用的数据。8K 是一个合理的缓冲区大小 - 不会大到您会浪费大量内存,也不会小到您必须使用大量浪费的 Receive 调用。4K 或 16K 也很可能会很好......我个人不会开始超过 16K 的网络缓冲区 - 我怀疑你很少填充它们。

You could experiment by trying to use a very large buffer and log how many bytes were received in each call - that would give you some idea of how much is generally available- but it wouldn't really show the effect of using a smaller buffer. What concerns do you have over using an 8K buffer? If it's performance, do you have any evidence that this aspect of your code is a performance bottleneck?

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

回答by antiduh

Jon Skeet's answer unfortunately leaves a big part of the picture out - the send buffer size, and the bandwidth-delay productof the pipe you're writing to.

不幸的是,乔恩·斯基特 (Jon Skeet) 的回答遗漏了大部分图片 - 发送缓冲区大小以及您正在写入的管道的带宽延迟乘积

If you are trying to send data over a large pipe using a single socket, and you want TCP to fill that pipe, you need to use a send buffer size that is equivalent to the bandwidth-delay product of the pipe. Otherwise, TCP will not fill the pipe because it will not leave enough 'bytes in flight' at all times.

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

Consider a connection that has a speed of 1 gigabit, and has a one-way latency of 10 milliseconds, on average. The round-trip-time (aka, the amount of time that elapses between your socket sending a packet and the time it receives the ack for that packet and thus knows to send more data) is usually twice the latency.

考虑一个速度为 1 Gb 且单向延迟平均为 10 毫秒的连接。往返时间(也就是,您的套接字发送数据包和它收到该数据包的确认并因此知道发送更多数据的时间之间经过的时间量)通常是延迟的两倍。

So if you have a 1 gigabit connection, and a RTT of 20 milliseconds, then that pipe has 1 gigabit/sec * 20 milliseconds == 2.5 megabytes of data in flight at all time if it's being utilized completely.

因此,如果您有 1 Gb 连接和 20 毫秒的 RTT,那么该管道将始终具有 1 Gb/秒 * 20 毫秒 == 2.5 兆字节的传输数据(如果它被完全利用)。

If your TCP send buffer is anything less than 2.5 megabytes, then that one socket will never fully utilize the pipe - you'll never get a gigabit/sec of performance out of your socket.

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

If your application uses many sockets, then the aggregate size of all TCP send buffers must be 2.5 MB in order to fully utilize this hypothetical 1 gigabit/20 ms RTT pipe. For instance, if you use 8192-byte buffers, you need 306 simultaneous TCP sockets to fill that pipe.

如果您的应用程序使用许多套接字,则所有 TCP 发送缓冲区的总大小必须为 2.5 MB,以便充分利用这个假设的 1 Gb/20 毫秒 RTT 管道。例如,如果您使用 8192 字节的缓冲区,则需要 306 个并发 TCP 套接字来填充该管道。

Edit for questions:

编辑问题:

Calculating BDP is just multiplying the Bandwidth times the Round-trip Delay and paying attention to units.

计算 BDP 只是将带宽乘以往返延迟并注意单位。

So if you have a 1 gigabit/sec connection, and a round-trip time of 20 msecs, then what happens is you're multiplying Bits/Sec * Seconds, so the seconds cancel out and you're left with Bits. Convert to Bytes and you have your buffer size.

因此,如果您有 1 Gb/秒的连接和 20 毫秒的往返时间,那么您将乘以 Bits/Sec * Seconds,因此秒数相互抵消,剩下的是 Bits。转换为字节,您就拥有了缓冲区大小。

  • 1 gbit/sec * 20 msec == 1 * gbit/sec * 0.02 sec == (1 * 0.02) gbit
  • 0.020 gbit == 20 MBit.
  • 20 Mbit * 1 Byte / 8 bits == 20 / 8 MBytes == 2.5 MBytes.
  • 1 gbit/sec * 20 ms == 1 * gbit/sec * 0.02 sec == (1 * 0.02) gbit
  • 0.020 gbit == 20 MBit。
  • 20 Mbit * 1 Byte / 8 bits == 20 / 8 MBytes == 2.5 MBytes。

And thus, our TCP buffer needs to be set to 2.5 MB to saturate this made-up pipe.

因此,我们的 TCP 缓冲区需要设置为 2.5 MB 以使这个组成的管道饱和。

回答by Justin Ethier

It depends upon your protocol. If you are expecting messages in excess of 8192 bytes, then you should increase your buffer size accordingly. But keep in mind this buffer size is only for one call to Receive. If you really want/need to, you can loop over Receivemultiple times and copy the received data into an arbitrarily large data structure or buffer.

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

Also keep in mind it is good practice to call Receiverepeatedly until you have verified that you have read all of the data for a given message; even if a single message is less than your buffer size, it still might not all be retrieved by a single Receivecall.

还要记住,Receive在您确认已阅读给定消息的所有数据之前,反复调用是一种很好的做法;即使单个消息小于您的缓冲区大小,它仍然可能无法通过单个Receive调用检索到。

回答by Robert ?pendl

Not really Microsoft related, but I am just experimenting with a C++ threaded echo server using a TCP port (not Unix domain socket) to see the throughput. Timing a 4M input with various buffer sizes gave the following results:

与 Microsoft 无关,但我只是尝试使用 TCP 端口(不是 Unix 域套接字)使用 C++ 线程回显服务器来查看吞吐量。使用各种缓冲区大小对 4M 输入进行计时得到以下结果:

1024 - real 0m0,102s; user  0m0,018s; sys   0m0,009s
2048 - real 0m0,112s; user  0m0,017s; sys   0m0,009s
8192 - real 0m0,163s; user  0m0,017s; sys   0m0,007s
 256 - real 0m0,101s; user  0m0,019s; sys   0m0,008s
  16 - real 0m0,144s; user  0m0,016s; sys   0m0,010s

Seems reading in 1024 byte chunks reduces the TCP overhead while the processing time (just echoing the input back) was not affected by the buffer size. 8192 bytes seem high and really low values (like 16) are not good either.

似乎读取 1024 字节块减少了 TCP 开销,而处理时间(只是回显输入)不受缓冲区大小的影响。8192 字节似乎很高,而非常低的值(如 16)也不好。

回答by ckv

8192 would be ideal. If you have data which exceed this size it would be better of you to send the data in constant length packets.

8192将是理想的。如果您有超过此大小的数据,最好以恒定长度的数据包发送数据。

The size of data that is sent by server can be checked using the recv function in WINSOCK which has a parameter that gives length of buffer.

可以使用 WINSOCK 中的 recv 函数检查服务器发送的数据的大小,该函数具有给出缓冲区长度的参数。