关于缓存buffer一个经典的解析

本文探讨了Linux系统中UDP缓冲区的配置与限制,详细解释了/proc/sys/net/core/rmem_max参数的作用,并分析了不同操作系统下UDP数据传输差异的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://bbs.chinaunix.net/thread-3777707-1-1.html


Q:通过查看/proc/sys/net/core/rmem_max,在B嵌入式设备上UDP最大缓冲区是32767字节,我想把它调大为65535
    请问各位大侠 /proc/sys/net/core/rmem_max Linux默认的UDP缓冲区大小修改之后,除了对内存产生影响外,其它还有什   么影响吗?

A:

rmem_max:控制的是你的socket接受收据的最大值(不限于TCP/UDP协议)。
这个数值的大小取决于你希望你的socket接受的数据的最大值。
比如:
     你希望通过socket来recv()数据的时候一次性拿多少。

其实内核在接受数据的时候会buffer接受好的数据
至于用户也就是你的应用程序希望一次性读多少取决于内核buffer的大小以及已经处理好的数据有多少。


协议栈不会调用setsockopt,而是由创建socket的应用程序调用。rmem_max是个内核调优参数,可以通过/proc/system/net/core/rmem_max进行调整。rmem_max是内核接受数据缓冲的大小,当然不是一次接受的大小,应用程序希望一次接受的大小是在recv()的参数来指定,但指定的这个大小最大是rmem_max,即内核会以rmem_max来缓存数据并在应用调用recv()的时候进行处理(如果recv()指定的大小大于rmem_max则将rmem_max的数据copy给应用;否则按照应用的要求大小进行copy)


/proc/sys/net/core/rmem_max 的含义是指内核最多为一个socket缓存多少数据。
比如你echo "65535" >  /proc/sys/net/core/rmem_max
减少A程序read这个socket,B程序从另一台服务器发送数据包,如果A的处理速度非常慢,B的发送速度非常快,当内核socket缓存超过65535字节后,B发送的数据包就会被A的内核丢弃。


1: Buffer size
       The maximum sizes for socket buffers declared via the SO_SNDBUF and SO_RCVBUF
       mechanisms are limited by the values in the /proc/sys/net/core/rmem_max and
       /proc/sys/net/core/wmem_max
 files.  Note that TCP actually allocates twice the
       size of the buffer requested in the setsockopt(2) call, and so a succeeding
       getsockopt(2) call will not return the same size of buffer as requested in the
       setsockopt(2) call.  TCP uses the extra space for administrative purposes and
       internal kernel structures, and the /proc file values reflect the larger sizes
       compared to the actual TCP windows.  On individual connections, the socket
       buffer size must be set prior to the listen(2) or connect(2) calls in order to
       have it take effect.  See socket(7) for more information.
由上文可看出,socket缓存大小不仅取决于setsockopt设置的大小,还受限于/proc/sys/net/core/rmem_max and /proc/sys/net/core/wmem_max


我看了协议栈代码,调用setsockopt时设置缓冲区时,是会与/proc/sys/net/core/wmem_max 比较的,这个我已经理解了。


Q:我还碰到一个问题,在Linux上(内核版本2.6.2)与windows XP上做了如下对比:
1):创建一个UDP套接字,发送缓冲区和接收缓冲区都设置为32K
2):Linux发送32K数据(用户数据),windows可以接收到32K,但是windows发32K数据,Linux接收不到,
  只有在发小于等于27K,Linux才可以接收到,测试数据如下:
我的疑问时,调用setsockopt设置的接收缓冲区不是用户可用的缓冲区吗?为什么Linux放不下那么大的数据呢?
Linux是不是又做过什么特殊处理?


UDP由于BUFFER SIZE引起的丢包问题
      参见《UNIX® Network Programming Volume 1》 中 8.13 Lack of Flow Control with UDP
注意如下描述:
    Why do we set the receive socket buffer size to 220 x 1,024 in Figure 8.22? The maximum size of a socket receive buffer in FreeBSD 5.1 defaults to 262,144 bytes (256 x 1,024), but due to the buffer allocation policy (described in Chapter 2 of TCPv2), the actual limit is 233,016 bytes. Many earlier systems based on 4.3BSD restricted the size of a socket buffer to around 52,000 bytes
    所以可以解答Linux 系统是32K 发送数据也是32K,为什么在27K时可以接收成功,看样子是由于BUFFER里面除了数据还包括一些头结构,导致真正可用数据不到32K.


Linux设置的这个缓冲区实际上不是用户可用的缓冲区,
Linux基于sk_buff数据结果进行网络数据收发,每个IP包都会有个sk_buff数据结果而且还包括整个的报文,因此会大大降低实际应用缓冲区,我发现2.6.16内核版本对
/proc/sys/net/core/wmem_max 默认值已经包含了sk_buff的大小,不知我说的对否?


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值