从大学有网络课程起就知道有三次握手这回事,但对其中到底发生了什么一直懵懵懂懂,今天打算借助 Wireshark 这一著名的网络数据包分析软件重现一下握手过程。
TCP 头部格式释义
字段对应关系及释义:
三次握手
关于 Wireshark
在 Wireshark 中左边实线(图中21 - 28、133 - 134、427 - 428)连起来的一段可以视为为同一次会话内发生的各个阶段,不过图中的是简单顺利的一次会话过程,没有失败重传、分片传输等其他情况。
另外:
- 每一条中的中括号的为 ACK 为通信控制位,后面的 ACK确认号 表示接收方当前接收到的字节数;
- SYN、FIN 控制位会占用一个确认号。
文中7001为服务器所在端口号。
三次握手之一
第21个网络包:客户端发送第一个网络包,在头部写入发送方、接收方端口号(用来找到目标套接字),设置客户端初始序号为0, SYN 控制位为1,等待服务器确认,由于此时客户端还未接收过网络包,所以 ACK 控制位为0。
三次握手之二
第22个网络包:服务器收到网络包,同样返回一个响应包,在TCP头部写入发送方、接收方端口号(此时对服务器来说是发送方)、服务端初始序号0, SYN 控制位1,另外还要设置 ACK 控制位为1,表示已收到有效网络包;除此之外可以注意到 ACK号 也被置为1了,就是上文提到的 SYN 控制位占用的一个确认号。
三次握手之三
第23个网络包:客户端收到网络包,发现 SYN 控制位为1,表示连接成功,同时发送一个 ACK 控制位设置为1的网络包给服务器,告知服务器刚才的响应包已收到,这里可以发现序号变为1,那是因为服务器返回的响应包中确认了客户端发送的 SYN 控制位为1,所以序号需要 +1;在服务器收到后三次握手就全部完成了,后面就可以开始收发数据了。
后面的[TCP Window Update]是用来窗口更新的,这里不做阐述。
收发数据
客户端发起请求
第25个网络包:客户端发起了一个 HTTP 页面请求,TCP详细信息如下:
可以看到这个网络包已经不单单是控制信息的传输,开始包含数据,并且数据占用621字节,同时 Wireshark 已经机智在计算下一个客户端发送的包序号了, 621…...
服务器发送确认包
然后服务器告知客户端已收到该请求,响应第26个网络包:
ACK号 = 前一次的 ACK号 + 本次收到的数据字节数 = 1 + 620 = 621;
序号保持不变,因为本次只是发送控制信息,并没有发送数据。
Tips:在 WireShark 选中某个网络包,如上图No.26,结果No.25前面出现了一个对勾,可以看作是No.26对No.25的消息确认。
服务器发送内容响应请求
在第27个网络包中,服务器针对HTTP请求返回页面内容:
可以看到这个网络包的数据大小为4152字节,这之后理论上在客户端应该会返回一个 ACK号 为4153的确认包。
客户端发送确认包
在第28个网络包中,序号就如前面 Wireshark 计算的等于621,ACK号的计算和第26个网络包相似,不再赘述。
关闭连接
在结束最后一个网络包的传输后,再过一段时间(上图中大概5秒),如没有数据往来Web服务器就会关闭连接,至于为什么要延时,大概是为了短时间内如果有后续数据交换,可以减少重新创建套接字建立连接的开销吧。
关闭连接握手之一
服务器生成包含断连控制信息 FIN 的TCP头部发送给客户端。
关闭连接握手之二
客户端告知服务器已收到断连信号 FIN , 因为收到的 FIN 占用一个确认号,所以回复的 ACK号 = 4153 + 1 = 4154。
关闭连接握手之三
客户端在读取所有缓冲区的数据后,也会向服务器发送一个 FIN 为1的网络包。
关闭连接握手之四
服务器同理返回 ACK号 确认收到 FIN 控制信息。
这就是断连操作的四次握手。
附测试数据
测试数据下载链接,过滤规则 tcp.port == 7001
。
该文章首发于我的个人站点
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。