去年老张推荐了两本林沛满写的关于wireshark抓包的书,分别是《wireshark就是这么简单》和《wireshark分析的艺术》,写的真心不错。
TCP协议是一个很有意思的内容,这半年对TCP协议有了更多的认识,于是想重新更新一些对TCP协议的内容。今天先从TCP协议里面的滑动窗口说起。
1、先说原理
就发送端来说,一般如下所示:
主要分为:已发送已确认的包(应用层未读取)。发送未确认的包,未发送可发送的包,未发送不可发送的包。
其中,滑动窗口指的是发送未确认和未发送可发送区域的大小。
2、滑动窗口
通常情况下,在wireshark抓包中看到的 win 表示向对方声明自己的接收窗口的大小,对方收到以后,会把自己的[发送窗口]限制在 指定大小之内。如果自己的处理能力有限,导致自己的接收缓冲区满,接收窗口大小为 0时发送端应该停止发送数据。
比如,使用模拟工具产生的TCP报文,其中客户端窗口声明为20,抓包如下:
第1~3包:三次握手过程,其中第一包是客户端向服务端发起连接,并声明自己的接收窗口为20字节。第2包为服务端返回的ACK+SYN,同时也声明了自己的接收窗口29200字节。第三包为客户端回复服务端的ACK,此时自己接口窗口还是20。此后开始正常的数据收发。
第4包:服务器端向客户端发送的第一次数据,15个字节。
第5包:客户端回复服务器自己收到报文的ACK,同时确认号为16,此时窗口还是为20字节。
第6包:服务器端向客户端发送第二次数据,16个字节。
第7包:客户端回复服务器端自己收到的报文ACK=32,此时窗口还是为20字节。
第8包:服务器端发送14个字节,此时滑动窗口中可用窗口为6个字节。
第9包:服务器端向客户端发送6个字节,此时可用窗口为0,wireshark识别出来,自动显示为[TCP Window Full]。
第10包:客户端确认了接收到的20个字节,可用窗口重现变为 20,因此重新声明自己的接收窗口win=20。
3 TCP Window Full
再比如,客户端发起连接的时候声明自己的窗口为4000,其中MSS为1000。然后模拟服务端发送5000字节数据给客户端。
第1~3包:三次握手。其中第1包是客户端声明自己的接收窗口为4000,MSS为1000自己。第2包是服务端回复的ACK+SYN。第3包为客户端回复的ACK。
第4包:服务端发送1000字节数据给客户端,1000个字节正好为一个MSS。
第5包:服务器端发送1000字节数据给客户端。
第6包:服务器端发送1000字节数据给客户端。
第7包:服务器端发送1000字节数据给客户端。此时服务器端被wireshark解析处理[TCP window Full]代表此时客户端的接收窗口已经满了。
第8包~11包:服务端超时未收到客户端发来的确认ACK,服务端启动重传数据。
4 Zero Window
当出现零窗口的时候,服务端启动持续探测定时器,也叫Persist定时器。
当接收端 B 接收窗口为 0 时,发送端 A 此时不能再发送数据,发送端此时开启 Persist 定时器,超时后发送一个特殊的报文给接收端看对方窗口是否已经恢复,这个特殊的报文只有一个字节。
比如某个wireshark的抓包结果如下:
第1~7包:包括了三次握手和正常通信数据包。
第8包:服务器端识别出客户端的接收窗口已经耗尽。
第9包:接收端回复的 ACK,携带了 win=0,wireshark 帮忙把这个包标记为了 TCP Zero window。
第10-25包:重传间隔是按照指数级退避,直到达到 120s 为止,一共重传尝试了16次(这个值由操作系统的参数决定),只是这里被wireshark标记为[TCP Keep-Alive]。
总结:
TCP Window Full 是站在发送端角度说的,表示此时发送端不能再发数据给对方,除非发送的数据包得到ACK。
TCP zero window 是站在接收端角度来说的,是接收端接收窗口满,自动告知对方不能再发送数据给自己。