网络协议(三) -- 三次握手与四次挥手

本文学习内容来源于掘金小册《深入理解TCP协议》与图书《TCP/IP详解卷I》,有兴趣的朋友可以购买相关小册进行更细致的学习

一:前情概述

TCP是可靠的、面向连接的、基于字节流的、双全工协议,耳熟能详的一句话概括了TCP协议所有重要的特性。面向连接的特性一定程度上保证了TCP协议的可靠性,横向对比同是传输层的无连接UDP协议。所以本文将讲述TCP协议进行数据传输通信前建立逻辑通道的故事,三次握手与四次挥手

在这里插入图片描述

二:认识协议头

应用层报文到传输层时,传输层会为其添加报文头,学习协议的开始应该由头开始。从协议头开始抽丝剥茧认识该协议,当然,本文讲述TCP协议的三次握手与四次挥手过程,所以只会列举与本文内容相关的字段
在这里插入图片描述

  • Source Port : 2字节、源端口(wireshark过滤表达式tpc.port就是这个原因)
  • Destination Port : 2字节、目标端口
  • Sequence number : 4字节、序列号(描述数据包开始座标)
  • Acknowledgment number : 4字节、确认码(描述确认数据包序列号 + 1,即下次数据包传送序列号开始座标)
  • Flags : 2字节、数据包类型标签,主要有如下表几种值
序号 标签种类 标签含义 备注
1 SYN 创建连接数据包 三次握手时传递
2 ACK 确认数据包 数据接收方收到数据包后确认通信的数据包
3 FIN 断开数据包 四次挥手时传递
4 RST 强制断开 某些不合法操作时强制断开连接返回数据包
5 PSH 传输层别缓存,立即将数据交给应用层

三:三次握手

在这里插入图片描述
开局一张图,故事全靠编。三次握手简而言之就是TCP为了建立逻辑连接,客户端与服务端进行三次通信的故事。中间过程伴随着信息交换状态变更等过程

3.1 信息交换

第一次握手、第一次应答时协议头中的Seq字段都是为了告诉连接对方数据包传输初始序列号。通过wireshark抓包截图可以看到都是0,很多文章都说这里是0开始。那么事情的真相到底是什么情况
在这里插入图片描述
通过tcpdump监控抓包显示三次握手过程中交换的seq信息并不是0开始,并且抓包过程重复几次你发现每次seq值都不一致。难道wireshark抓包信息有误?并不是,seq初始值的生成算法会根据时间变化计算取得,wireshark中为了方便查看相对计算为0、1进行表达。若想恢复算法值如下所示:Edit(编辑E) – Preferences(首选项P) – Protocols – TCP
在这里插入图片描述
在这里插入图片描述
当然为什么会采用这样的算法计算得出这样一个数值,每次从一个固定的序列号开始不好么?这个问题后面章节详细讨论。至于ACK就显得很简单了,每次收到数据包后进行相对应的确认,数据传输方可以根据是否确认决定是否进行重传等操作。ACK数值一定是seq + 1,前面讲了ACK还表示下次数据传输开始序列号

信息的交换当然不仅仅是初始化序列化交换这么简单,如最大段大小(MSS)、窗口大小(Win)、窗口缩放因子(WS)、是否支持选择确认(SACK_PERM)也会在握手过程中交互。但是本文主要目的为讲解三次握手过程,所以相关内容留待后续解决

3.2 状态变更

创建连接的过程中必然伴随着状态的变更,不然鬼知道到了哪一步该执行什么样的操作。简要步骤描述如下所示:

  1. 双方处于CLOSED关闭状态,然后服务端启动应用将某端口变更为LISTEN监听状态
  2. 客户端第一次握手发送SYN包,状态调整为SYN-SENT
  3. 服务端接收到SYN请求包,进行SYN+ACK操作。状态变更为SYN-RCVD
  4. 客户端收到服务端的请求确认后进行ACK响应操作,状态变更为ESTABLISHED就绪
  5. 服务端接收到客户端的ACK确认包状态变更为ESTABLISHED就绪,双方连接建立成功

四:握手详解

三次握手的过程通过第三章已经基本清楚,但是也带来了新的问题:

  • 三次握手是否可以修改为两次
  • 初始序列号是否可以固定值
4.1 可否两次握手

对于为什么选择三次握手这个数字,通过前面的内容说实话不会回答的很好。这个答案结合后续的知识在这里作答个人理解如下:

  • 除去第二次握手交互,即服务端到客户端的SYN + ACK。那么客户端将不会知道服务端是否收到连接SYN请求,也就无法进行超时重传。当然如果这时候直接进行正式数据包的传输,服务端无法接收同时也浪费客户端资源
  • 除去第三次握手交互,服务端不清楚客户端是否确认准备就绪,占用服务端资源。连接队列里的连接将一直得不到利用以及释放,新连接将因为溢出而无法连接,整个应用崩溃无法提供服务
4.2 序列号固定

TCP连接四元组为源IP、源端口、目的IP、目的端口,即初始序列号唯一固定也不会影响TCP连接。但是注意一点,获取应用IP与端口是十分简单的操作,当知道所有信息之后模拟RST包(强制关闭)将十分容易,连接安全也就没法进行保证

同时,如果启用了SO_REUSEADDR(端口复用)。很容易导致新连接与旧连接数据包串包,谁也没法保证接收到的数据包是否因为网络原因而延迟的旧连接数据包

五:四次挥手

在这里插入图片描述
四次挥手相对于三次握手多了两个关键的节点,这两个关键的节点将是本章学习重点。添加这两个过程状态的原因是什么?中间都发生了什么故事?

5.1 两次回复

前面接触三次握手的时候服务端接收到客户端发送的SYN包后将会返回SYN+ACK,即同时进行确认与连接。但是,四次挥手过程示意图中这个步骤分解为两步。首先进行ACK确认,然后再进行FIN关闭。

原因如下:

当客户端发送FIN包后会启动定时器,当定时器时间到达时会重发FIN包。但是这时候服务端有可能数据并未传输完毕,如果等待数据传输完毕以后再统一返回FIN+ACK可能导致客户端多次发送FIN。所以四次挥手过程中将先对客户端FIN进行确认,等待数据传输完毕时再执行FIN

5.2 TIME-WAIT

比较神奇的一个状态,主动断开连接的一方将进入该状态。问题来了,既然都已经断开连接了为什么还要藕断丝连,何不果断点?

  • 一方面因为网络延迟,需要等待连接所有数据包失效
  • 一方面因为需要处理最后ACK丢包情况的发生

TCP协议头中存在字段MSL(Max Segment Lifetime)即数据包生存最大时长,这个最大时长就是数据包在网络中可以存在的最大时间。如果老连接不等待MSL时间,那么新的连接就可能接收到因为网络延迟原因抵达的老连接数据包。这样的数据包新连接无法进行正确的处理。2MSL原因是最大程度计算保证来回的时长,下图复制来源于张师傅掘金小册内容,学习相关内容请购买小册进行学习
在这里插入图片描述
因为网络原因,服务端发出FIN后并未收到客户端确认的ACK。将会导致服务端处于LAST-ACK状态,定时器到达时间后重发FIN包,若这时客户端已经关闭,将会导致服务端持续重发FIN包,直到最大次数限制,这将会消耗服务端资源。2MSL时长能保证服务端的FIN重发包到达客户端,客户端重新进行ACK

在这里插入图片描述

六:分手详解

对于TCP四次挥手谈及最多的内容当属是否可以三次挥手?为什么要等待两个MSL时间?第二个问题在前面已经有了答案,第一个问题解释如下:
在这里插入图片描述
大清亡了?为嘛FIN和ACK搞一块去了?任何结论都需要实践的基础,wireshark抓包的结果告诉我们,如果当服务端没有数据进行传输时,是可以将FIN与ACK在同一个包中传输,即三次挥手既视感。这与三次握手异曲同工,所以三次握手如果开心也可以设计为四次握手,将SYN与ACK拆开,当然这样的操作必然代码性能的消耗

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章