linux内核TCP 滑动窗口,TCP滑动窗口和流控

TCP的滑动窗口是一个很重要的概念,也是很晦涩的一个知识点。下面就大概介绍下TCP滑动窗口为什么出现?它是怎么工作的的?

什么是TCP窗口

首先,要理解,client和server各自协议栈都有自己的buffer,应用层读写数据的源都是协议栈buffer里。以接收端为例,应用程 序调用read()时,会从buffer里移走数据到用户空间,应用程序读的速度越快(read(1024)必然比read(1)要快),那么 buffer里的内容消费的越快,buffer也会越空。那么TCP就可以告诉client,我现在很闲,你可以发送更多的数据来。"更多"是多少?这就 说窗口,窗口就是量化接收端和服务端当前能处理数据的能力。

TCP窗口是如何工作的

client和server端建立连接后,client会告诉server,自己的"接收窗口"大小(自己能接收多少的数据,受上面所说的 buffer影响),server端接收到client的"接收窗口"大小,就会变成server端自己的"发送窗口"大小。同样的,server端告诉 client自己的"接收窗口"大小,就会变成客户端的"发送窗口"大小。

为了理解TCP的窗口大小是怎么样变化的,我们先需要理解它的含义。最简单的方式就是认为窗口大小"意味着接收方能接收数据的大小",这也是说接收 端设备再应用程序读取buffer中数据之前,能从对端连接处理多少数据。比如说server端窗口大小是360,那么就意味着server端一次只能从 客户端接收不超过360bytes的数据。当server端收到数据,它会将数据放到buffer里,然后server端必须对这份数据做两件事

1. server端必须发送一个 ACK 到client端来确认数据已经收到

2. server端必须处理这份数据,把它交给对应的应用程序

要区分上面两件事对理解窗口很重要,接收方收到数据后会确认,但是数据并不一定是里面就是从buffer里取出的,这是受应用层逻辑控制的。所以很 有可能如果接收数据过快,而取出数据更慢,就会导致buffer满。一旦这种情况发生,窗口大小就开始调整来防止接收方负载过高。

正是因为窗口大小的调整可以用来调节数据传输的速率,所以就可以实现TCP的流控,在传输层的流控就是典型的例子,流控对于TCP的通信是很重要的,通过增大或者减小窗口的大小,client和server各自确保彼此设备发数据和收数据平衡。

通过TCP窗口实现流控

下面举一个例子,来看TCP窗口大小变化怎样实现流控。client端和server端已经三次握手建立TCP连接,总窗口大小是TCP建立连接时 候确定的。黑色框代表client和server总的窗口大小,红色框代表实际可用的窗口大小。初始化的时候默认client和server总窗口和可用 端口分别都是360。另外,假设Client总共只发送360bytes数据,所以总窗口大小不会往前移动。

70c3a4e1304516db4ac88493b02c2c60.png

client 发送140bytes到server端,Seq=1,Length=140;可用窗口大小往前移动,变成260bytes,总窗口大小不变,依然是360。这中间的120是已发送,等待确认;

server端收到140bytes,放入buffer中,但是应用程序很繁忙,只取出100个字节。这时候可用窗口大小: 260(360-100)。接着server端要给client发确认,Ack=141,Window=260。黑框左边缘向前移动,表示140字节已经 确认收到,但是应用程序太慢,处理很忙导致我现在只能处理260bytes(回顾下上面server端收到数据要做的两件事);

client收到来自server端的ack回应,首先总窗口左边缘向前移动,表示第一步的140bytes server已经收到,剩下260数据。接着被告知server的可接收窗口是260,client就调整自己的发送窗口是260,表示一次发数据不能超 过260;

client发送180bytes,可用窗口变成80(260-180),等待确认发送的180bytes;

server收到180bytes,放入buffer中,应用程序依然很繁忙,这次一个字节都不处理。此时可用窗口大小:80(260-180),然后发180 ack给client,并告知窗口大小80;

client收到ack,确认之前发送的180已经到达,剩余数据还有80字节。被告知server端接收窗口大小是80,调整自己的发送窗口大小为80

client发送80bytes,可用窗口变成0(80-80),等待确认发送的80bytes;

server收到180bytes,放入buffer中,应用程序依然很繁忙,一个字节都不处理。此时可用窗口大小:80(80-80),然后发80 ack给client,并告知窗口大小0;

client收到ack,确认之前发送的80已经到达。被告知server端接收窗口大小是0,调整自己的发送窗口大小为0,此时无论client是否还有数据要发送,都不能再发了。

总结

窗口就是量化接收端和服务端当前能处理数据的能力。个人理解,如发现接收端的窗口越来越小,或者越来越大,都可能会有问题。

1. 接收端的窗口越来越小,那么就是接收端处理不过来(1.发的程序太快,太多;2.收的程序太慢,太少;3.发端带宽比收端带宽更大),会导致接收端发送给发送端的窗口变小,从而发送端调整发送窗口大小,降低发送速度,网络流量就会下降。

2. 接收端的窗口越来越大,那么就是发送端处理不过来(1.收的程序太快,太多;2.发的程序太慢,太少;3.发端带宽比收端带宽更小),会导致接收端发送给发送端的窗口变大,从而发送端调整发送窗口大小,增加发送速度,网络流量就会升高。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户/服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八章点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信号量 信号量集结构 信号量集函数 信号量示例 31System V信号量(二) 用信号量实现进程互斥示例 32System V信号量(三) 用信号集解决哲学家就餐问题 33System V共享内存与信号量综合 用信号量解决生产者消费者问题 实现shmfifo 34POSIX消息队列 POSIX消息队列相关函数 POSIX消息队列示例 35POSIX共享内存 POSIX共享内存相关函数 POSIX共享内存示例 Linux网络编程之线程篇 36线程介绍 什么是线程 进程与线程 线程优缺点 线程模型 N:1用户线程模型 1:1核心线程模型 N:M混合线程模型 37POSIX线程(一) POSIX线程库相关函数 用线程实现回射客户/服务器 38POSIX线程(二) 线程属性 线程特定数据 39POSIX信号量与互斥锁 POSIX信号量相关函数 POSIX互斥锁相关函数 生产者消费者问题 自旋锁与读写锁介绍 40POSIX条件变量 条件变量 条件变量函数 条件变量使用规范 使用条件变量解决生产者消费者问题 41一个简单的线程池实现 线程池性能分析 线程池实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值