TCP系列36—窗口管理&流控—10、linux下的异常报文系列接收
在这篇文章中我们看一下server端在接收到异常数据系列时的处理,主要目的是通过wireshark示例对这些异常数据系列的处理有一个直观的认识,感兴趣的自行阅读相关代码和协议,这里不再进行详细介绍
在进行下面的测试前,首先如下设置相关的参数,其中window参数指定了到127.0.0.2的tcp连接的最大接收窗口。
root@Inspiron:/home/******/tcp12# ip route change local 127.0.0.2 dev lo window 40
一、wireshark示例
1、一个包部分数据在rcv_nxt后
如下图所示,client在与server建立连接后,首先发出No4数据包,系列号对应[1,10],下图中text列表示这个TCP数据包中实际传输的数据,No4的len=10,应用层实际传输的数据内容为"0123456789"。接着client又在No6数据包中传输系列号为[6,15]的数据包,传输的内容同样为"0123456789",长度同样为10bytes。
可以看到这里No4和No6两个数据包部分系列号重复,No4数据包系列号[6,10]对应字符串"56789",而No6数据包系列号[6,10]对应字符串"01234"。server端对于No6数据包正常回复了一个ACK报文,Ack=16,也就是说确认了系列号16以前的数据,同时可以看到No7这个ACK确认包还带有一个DSACK块,指示发送端收到了重复报文。
最终server端应用层实际读取了15bytes数据,内容为"012345678956789",可见server端把No6报文系列号[6,10]对应的数据丢弃了,但是保留了系列号[11,15]的内容。
2、一个乱序包完全在接收窗口外
如下图所示,client在与server端建立连接后,首先正常发送No4报文,接着发送乱序报文No6。从No5这个确认包可以看到Ack+Win=51,也就是说从系列号51开始的数据都是接收窗外外部的数据(包括系列号51对应的byte)。No6报文对应的系列号为[51,60]正好完全处于接收窗口外部,因此server端会丢失No6这个数据包。server端应用层最终读取了10bytes的数据,即"0123456789"。
3、一个乱序包部分在接收窗口外
这个示例与上一个不同之处在于No6系列号范围为[46,55],也即这个数据包[46,50]系列号在接收窗口内,而[51,55]在接收窗口外部。
接着看No7,No7通过SACK完整的确认了No6数据包,把落在接收窗口外部的[51,55]系列号也完整确认了,注意这个示例与上面的对比。当乱序包部分系列号落在接收窗口外部的时候,linux会正常完整的接收这个数据包,包括落在接收窗口外部的数据。而当这个数据包完全落在接收窗口外部的时候,linux则不会接收这个数据包。
另外值得注意的是No8-No11四次挥手关闭连接的过程,No8携带了SACK信息,No9则回复了一个ACK,注意No10这个FIN包的起始系列号为11,server端正常的接收了这个数据包,这也就意味着server端会把收到乱序No6报文丢掉,应用层并不能成功读取。
4、快速路径下连续包落在接收窗口外
linux对于接收到的数据包处理流程分为快速路径和慢速路径,在接收到紧急指针、tcp头中的window size发生变化等场景下都会进入慢速处理路径,慢速路径相比快速路径会执行更多检查处理。我们先来看一下快速路径下,连续包落在接收窗口外部的情况。为了不让server端更新接收窗口,我们通过SO_RCVBUF选项固定server端的接收缓存,同时我们通过特定的数据包让server端进入delay ACK模式。执行下面的测试前取消通过路由表设置的window参数。
相关的数据交互如下,No4数据包用来触发server端快速的进入delay ACK模式,server回复完No5这个确认包后就会进入delay ACK模式。关于delay ACK相关内容可以参考前面的文章。同时注意No5报文通告的Win=2,也就是接收窗口只剩余2bytes。
接着我们看到client端发送的No6-No32报文都没有触发server端回复ACK确认包。其中No6报文部分落在接收窗口外部,而No7-No32报文都是完全落在接收窗口外部的数据包。从No34这个确认包可以看到server端对于部分落在接收窗口内部的No6和完全落在接收窗口外部的No7-No32都接收了。而对于No33则没有进行接收,随后在发送No35数据包server端也没有接收。
这里No6-No32能被正常接收的原因是,linux中TCP会预留一定的缓存,当在快速处理模式下时候并不会执行严格的检查,只要新接收的数据包所占用的缓存没有超过预留的缓存就会正常接收。No6-No32都没有超过预留的缓存,因此server端正常接收。但是server端在接收到No34的时候,预留缓存不足,就会直接丢弃这个数据包,并进入quick ACK模式立即回复一个ACK,可以看到No34是一个零窗ACK报文,因此server端也就退出数据包的快速处理模式,随后在收到No35的时候会进入数据包慢速处理流程,执行检查的时候发现此时接收窗口大小为0,No35落在了接收窗口外面,因此同样会直接丢弃这个数据包并立即回复一个ACK确认包。
5、慢速路径下连续包落在接收窗口外
实际上上一次示例No35的处理已经是在慢速路径下处理的了。我们在看另外一个类似的示例。下图示例中No1-No15报文的处理与上面的示例类似,不同的地方在于No16这个数据包的Win发生了更新。server端在收到No16这个数据包的时候,发现No16更新了window size就会退出快速路径的处理进入慢速路径,以执行更复杂的检查和处理。在慢速路径中server端发现No16落在的接收窗口外部,因此直接丢弃这个数据包并进入quick ACK模式立即回复一个No17确认包,回复No17确认包的时候发现Win=0,server端TCP则退出数据包的快速处理模式,在随后接收到新数据包的时候则直接进入慢速路径处理。

6、乱序包内容部分重叠
如下图所示,client依次发送5个数据包,相关TCP交互如下图所示

为了方便对比,我把五个数据包对应的做如下图展示,其中第一行表示系列号比特位,第二行表示server端应用层实际读取的数据流,余下的5行分别表示client依次发送的5个数据包,其中数据包的红色部分表示最终被server端丢弃,数据包的绿色部分表示最终被server端接收。从下图可以看到一旦一个新接收的报文与之前报文重叠的时候,如果是新接收报文的前端发生重叠,那么新接收报文的前端内容会被丢掉,如果是后端重叠,那么之前接收的报文的内容将会被丢掉。
补充说明:
1、linux相关函数数据包接收处理:tcp_rcv_established、tcp_data_queue、tcp_data_queue_ofo
2、慢速路径快速路径等相关函数:tcp_fast_path_check,重点是tp->pred_flags这个标志变量在不同地方的更新
TCP系列36—窗口管理&流控—10、linux下的异常报文系列接收的更多相关文章
- TCP系列27—窗口管理&流控—1、概述
在前面的内容中我们依次介绍了TCP的连接建立和终止过程和TCP的各种重传方式.接着我们在这部分首先关注交互式应用TCP连接相关内容如延迟ACK.Nagle算法.Cork算法等,接着我们引入流控机制(f ...
- TCP系列31—窗口管理&流控—5、TCP流控与滑窗
一.TCP流控 之前我们介绍过TCP是基于窗口的流量控制,在TCP的发送端会维持一个发送窗口,我们假设发送窗口的大小为N比特,网络环回时延为RTT,那么在网络状况良好没有发生拥塞的情况下,发送端每个R ...
- TCP系列35—窗口管理&流控—9、紧急机制
一.概述 我们在最开始介绍TCP头结构的时候,里面有个URG的标志位,还有一个Urgent Pointer的16bits字段.当URG标志位有效的时候,Urgent Poinert用来指示紧急数据的相 ...
- TCP系列32—窗口管理&流控—6、TCP zero windows和persist timer
一.简介 我们之前介绍过,TCP报文中的window size表示发出这个报文的一端准备多少bytes的数据,当TCP的一端一直接收数据,但是应用层没有及时读取的话,数据一直在TCP模块中缓存,最终受 ...
- TCP系列34—窗口管理&流控—8、缓存自动调整
一.概述 我们之前介绍过一种具有大的带宽时延乘积(band-delay product.BDP)的网络,这种网络称为长肥网络(LongFatNetwork,即LFN).我们想象一种简单的场景,假设发送 ...
- TCP系列28—窗口管理&流控—2、延迟ACK(Delayed Acknowledgments)
一.简介 之前的内容中我们多次提到延迟ACK(Delayed Ack),延迟ACK是在RFC1122协议中定义的,协议指出,一个TCP实现应该实现延迟ACK,但是ACK不能被过度延迟,协议给出延迟AC ...
- TCP系列33—窗口管理&流控—7、Silly Window Syndrome(SWS)
一.SWS介绍 前面我们已经通过示例看到如果接收端的应用层一直没有读取数据,那么window size就会慢慢变小最终可能变为0,此时我们假设一种场景,如果应用层读取少量数据(比如十几bytes),接 ...
- TCP系列29—窗口管理&流控—3、Nagle算法
一.Nagle算法概述 之前我们介绍过,有一些交互式应用会传递大量的小包(称呼为tinygrams),这些小包的负载可能只有几个bytes,但是TCP和IP的基本头就有40bytes,如果大量传递这种 ...
- TCP系列30—窗口管理&流控—4、Cork算法
一.Cork算法概述 Cork算法与Nagle算法类似,也有人把Cork算法称呼为super-Nagle.Nagle算法提出的背景是网络因为大量小包小包而导致利用率低下产生网络拥塞,网络发生拥塞的时候 ...
随机推荐
- C# 发送Http协议 模拟 Post Get请求
1.参数 paramsValue的格式 要和 Reques.ContentType一致, 如果 contentype "application/x-www-form-urlencoded& ...
- 最新版的stm32f1xx.h文件中取消了u8, u16, u32的类型定义
使用芯片stm32f103zet6和stm32l151c8t6,在移植程序时发现,编译器提示u8未定义: 在Keil MDK 开发环境里,st定义无符号32位整形数据有很多种表示方法: 1 unsig ...
- Python中常见的字典dict处理
#字典的赋值d = [{"dasda": 123, "gsgsg": 3344}, {"dasdz": 123, "gsksg&q ...
- FPGA基础知识,应用,ASIC、ASSP区别(四)
一.ASIC与ASSP区别? 专用应用集成电路( ASIC) 是一种由电子组件组成的集成电路,例如 :晶体管.电容器.电阻器等,这些组件被植入到晶元上 :晶元由硅或其他半导体材料组成,并可按照特定用途 ...
- 关于verilog中的signed类型
在数字电路中,出于应用的需要,我们可以使用无符号数,即包括0及整数的集合:也可以使用有符号数,即包括0和正负数的集合.在更加复杂的系统中,也许这两种类型的数,我们都会用到. 有符号数通常以2的补码形式 ...
- Solr与Lucene的区别
Lucene是一个优秀的开源搜索库,Solr是在Lucene上封装的完善的搜索引擎.通俗地说,如果Solr是汽车,那么Lucene就是发动机,没有发动机,汽车就没法运转,但对于用户来说只可开车,不能开 ...
- jsp内置的对象【jsp可用数据容器】
jsp的内置对象用法:可以存放数据进去,本身页面可以调用,发生页面请求时,请求目标可以调用 理解:jsp就是一个大容器,有请求,响应等内置对象,会话需要从请求容器中提取 请求中内置session,发出 ...
- BZOJ1222_ 产品加工_KEY
题目传送门 我们设f[i]表示用机器A加工,时间还剩下i时的最优加工时间. 对于每一个时间可以加工的物品,有以下几个选择: 1.用机器A加工 2.用机器B加工 3.A和B一起加工 所以得到方程: f[ ...
- 北京Uber优步司机奖励政策(12月20日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 01-JVM内存模型:程序计数器
一.JVM模型概述 java虚拟机(JVM)在java程序运行的过程中,会将它所管理的内存划分为若干个不同的数据区域,这些区域有的随着JVM的启动而创建,有的随着用户线程的启动和结束而建立和销毁.一个 ...