当前位置:网站首页>Socket发送缓冲区接收缓冲区快问快答
Socket发送缓冲区接收缓冲区快问快答
2022-08-09 21:55:00 【恐龙弟旺仔】
1.Socket发送数据的全过程
首先,我们要明确一下,通过socket发送数据之后(调用发送方法),数据并不是会直接发送到接收方。
整个过程简略图如下:

最终数据发送是要通过网卡的,但是socket没法直接将数据发送到网卡,所以只能先将数据发送到操作系统数据发送缓冲区。
然后网卡从数据发送缓冲区中获取数据,再发送到接收方。
2.socket接收数据的全过程
socket接收数据,也不是直接从对端获取的。
整个过程简略图如下:

首先接收方机器网卡接收到发送方的数据后,先将数据保存到操作系统接收缓冲区。
client端感知到操作系统缓冲区的数据后,主动调用接收数据的方法来获取数据。
3.接收缓冲区、发送缓冲区的含义
首先,这两个区域是每一个Socket连接都有的。本质上而言,就是内核中的两块内存空间,socket创建完成后,这两块内存空间就开辟出来了。
至于其作用,如上图所示,主要是为了做数据缓冲区用的。
4.接收缓冲区、发送缓冲区需要设置嘛?
一般情况下,我们不需要主动设置(当然,也不建议主动设置这两个区域)。
貌似在我们的代码中,从来没有主动设置过这两个区域。
5.接收缓冲区、发送缓冲区默认大小是多少呢?
既然我们没有主动设置过,那么平时我们怎么知道,这两块区域的占用内存大小是多少呢。
就java技术栈而言,我们可以通过获取Socket的属性来获取
Socket socket = new Socket();
int sendBufferSize = socket.getSendBufferSize(); // 发送缓冲区
int receiveBufferSize = socket.getReceiveBufferSize(); // 接收缓冲区笔者在Windows电脑上测试,默认输出都是65536,也就是64KB。
Linux系统下,我们可以通过查看参数来获取默认值
[[email protected]_netstorage core]# cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 131072 //写缓冲区大小 第一个表示最小值,第二个表示默认值,第三个表示最大值。
[[email protected]_netstorage core]# cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 174760 //读缓冲区大小 第一个表示最小值,第二个表示默认值,第三个表示最大值。6.可以主动设置读写缓冲区大小嘛?
肯定是可以的。
在java栈中,我们可以通过如下方式设置
Socket socket = new Socket();
socket.setSendBufferSize(size); // 设置写缓冲区大小
socket.setReceiveBufferSize(size); // 设置读缓冲区大小但是这个设置是不能超过系统设置参数的。
以下解释来自于: 高性能网络编程7--tcp连接的内存使用_陶辉的博客-CSDN博客
SO_SNDBUF、SO_RCVBUF都是个体化的设置,即,只会影响到设置过的连接,而不会对其他连接生效。SO_SNDBUF表示这个连接上的内核写缓存上限。
实际上,进程设置的SO_SNDBUF也并不是真的上限,在内核中会把这个值翻一倍再作为写缓存上限使用。
我们不需要纠结这种细节,只需要知道,当设置了SO_SNDBUF时,就相当于划定了所操作的TCP连接上的写缓存能够使用的最大内存。
然而,这个值也不是可以由着进程随意设置的,它会受制于系统级的上下限,当它大于上面的系统配置wmem_max(net.core.wmem_max)时,
将会被wmem_max替代(同样翻一倍);而当它特别小时,例如在2.6.18内核中设计的写缓存最小值为2K字节,此时也会被直接替代为2K。
SO_RCVBUF表示连接上的读缓存上限,与SO_SNDBUF类似,它也受制于rmem_max配置项,实际在内核中也是2倍大小作为读缓存的使用上限。
SO_RCVBUF设置时也有下限,同样在2.6.18内核中若这个值小于256字节就会被256所替代。7.设置了读写缓冲区,是否就是一定会使用这么多内存呢?
以下解释来自于: 高性能网络编程7--tcp连接的内存使用_陶辉的博客-CSDN博客
TCP连接所用内存主要由读写缓存决定,而读写缓存的大小只与实际使用场景有关,在实际使用未达到上限时,SO_SNDBUF、SO_RCVBUF是不起任何作用的。
对读缓存来说,接收到一个来自连接对端的TCP报文时,会导致读缓存增加,当然,如果加上报文大小后读缓存已经超过了读缓存上限,那么这个报文会被丢弃从而读缓存大小维持不变。
什么时候读缓存使用的内存会减少呢?当进程调用read、recv这样的方法读取TCP流时,读缓存就会减少。
因此,读缓存是一个动态变化的、实际用到多少才分配多少的缓冲内存,当这个连接非常空闲时,且用户进程已经把连接上接收到的数据都消费了,那么读缓存使用内存就是0。
写缓存也是同样道理。当用户进程调用send或者write这样的方法发送TCP流时,就会造成写缓存增大。当然,如果写缓存已经到达上限,那么写缓存维持不变,向用户进程返回失败。
而每当接收到TCP连接对端发来的ACK确认了报文的成功发送时,写缓存就会减少,这是因为TCP的可靠性决定的,发出去报文后由于担心报文丢失而不会销毁它,
可能会由重发定时器来重发报文。因此,写缓存也是动态变化的,空闲的正常连接上,写缓存所用内存通常也为0。
因此,只有当接收网络报文的速度大于应用程序读取报文的速度时,可能使读缓存达到了上限,这时这个缓存使用上限才会起作用。
所起作用为:丢弃掉新收到的报文,防止这个TCP连接消耗太多的服务器资源。
同样,当应用程序发送报文的速度大于接收对方确认ACK报文的速度时,写缓存可能达到上限,从而使send这样的方法失败,内核不为其分配内存。
8.在实际开发中,我们是否推荐设置读写缓冲区大小呢?
答案是:不推荐。
我们考虑以下实际场景:
当连接到服务端的连接比较少时,我们期望设置该连接的读写缓冲区大小为系统缓存上限,这样便可以充分利用网络资源;
当连接到服务端的连接比较多时,这时系统内存为稀缺资源了,为了支持更多的连接,便需要减小每个连接的读写缓冲区大小;
为了支持这种场景,Linux操作系统实现了自动调整分配内存的功能。由以下参数来决定
net.ipv4.tcp_moderate_rcvbuf = 1 # 默认tcp_moderate_rcvbuf配置为1,表示打开了TCP内存自动调整功能。若配置为0,这个功能将不会生效但是,如果我们主动配置了socket读写缓冲区大小,那么这个自动分配内存的功能就不再生效。
9.发送缓冲区、接收缓冲区与发送窗口、接收创建之间的关系?
需要先明确下:
发送缓冲区>=发送窗口
如下图所示:(图片来自: TCP缓存区与窗口的关系_ccc_yxc的博客-CSDN博客_发送窗口和发送缓存 )

发送窗口只是发送缓冲区的一部分,已经被确认的数据则会从发送缓冲区中删除。
接收缓冲区>=接收窗口
如下图所示:(图片来自: TCP缓存区与窗口的关系_ccc_yxc的博客-CSDN博客_发送窗口和发送缓存 )

接收缓冲区中存放的数据,一旦被应用程序读取到之后,则会从缓冲区中删除。
参考:
socket tcp缓冲区大小的默认值、最大值_zzd2018的博客-CSDN博客_socket接收缓冲区最大值
高性能网络编程7--tcp连接的内存使用_陶辉的博客-CSDN博客
TCP缓存区与窗口的关系_ccc_yxc的博客-CSDN博客_发送窗口和发送缓存
边栏推荐
猜你喜欢

Leetcode.25 K个一组翻转链表(模拟/递归)

How do task flow executors work?

JS解混淆-AST还原案例

Postgresql源码(68)virtualxid锁的原理和应用场景

4D Summary: 38 Knowledge Points of Distributed Systems

shell学习

SQLi-LABS Page-2 (Adv Injections)

ACM MM 2022 | Cloud2Sketch: Painting with clouds in the sky, AI brush strokes

TF generates uniformly distributed tensor

国内手机厂商曾为它大打出手,如今它却最先垮台……
随机推荐
阿里云架构师金云龙:基于云XR平台的视觉计算应用部署
In-depth analysis of Apache EventMesh cloud-native distributed event-driven architecture
typedef和#define的花里胡哨的用法
TF uses constant to generate data
【LaTex】 Font “FandolSong-Regular“ does not contain requested(fontspec)Script “CJK“.如何抑制此种警告?
面试官:MySQL 中 update 更新,数据与原数据相同时会执行吗?大部分人答不上来!
2022 首期线下 Workshop!面向应用开发者们的数据应用体验日来了 | TiDB Workshop Day
Use zeros(), ones(), fill() methods to generate data in TF
肝通宵写了三万字把SQL数据库的所有命令,函数,运算符讲得明明白白讲解,内容实在丰富,建议收藏+三连好评!
[Cloud Native] 4.2 DevOps Lectures
1215 – Cannot add foreign key constraint
Cesium渐变色3dtiles白模(视频)
abstract class or interface
JS–比想象中简单
小程序+自定义插件的关键性
navicat 快捷键
Rust dereference
Flask's routing (app.route) detailed
Shanghai Konan SmartRocket series product introduction (3): SmartRocket iVerifier computer interlocking system verification tool
【微服务~Nacos】Nacos服务提供者和服务消费者