网上 关于 TCP三次握手 的文章有很多,但很多一些部分讲的含糊其辞,所以才重新造了这个轮子,一方面对那些含糊其辞的部分做了解释,另一方面也方便了以后的学习。
1、上图的名词解释
- SYN:同步序号。
它表示建立连接
。TCP规定SYN=1时不能携带数据,但要消耗一个序号, 因此随机选取一个序列号为seq=x 数据包(该数据包里就是一个标记seq,并没有任何有效的数据)。
- ACK :确认序号。
它表示响应
(都能响应了 那肯定上一步就连接成功了啊,所以说ACK=1代表确认连接成功啦)。
因此SYN和ACK同时为1,表示建立连接之后的响应
;而只是单个的SYN=1,表示的只是建立连接
。
- seq: (sequence number) 序列号。它是发送端数据包的初始序号。
seq=x 表示发送端数据包的初始序号为x
(seq = 0 就代表这是第0号帧)。
- ack:(acknowledge number) 确认号。它是对这次收到数据包的确认,以及对下次收到数据包的期待。
ack=x+1表示 我方 到 x为止的所有数据都已正确收到,且我方告知 对方:我期待你下次给我发送包的初始序号(seq)是x+1
。
为了方便记忆,可以这么理解:SYN/ACK是TCP协议层面的标记,而seq/ack是数据层面的标记。
2、TCP三次握手 过程
( 1 )首先Client向Server发送连接:SYN = 1, seq=x;
-
因为
要建立连接,所以SYN=1
;又因为
TCP规定SYN=1时不能携带数据,但要消耗一个序号, 所以
Client随机选取一个初始序号seq=x
。(因为并没有响应动作,所以这里没ACK什么事,我们就认为ACK=0吧)
- 发送后Client进入syn_sent状态,表示客户端等待服务器的回复。
(2)Server收到请求后 再向Client发送确认:SYN=1, ACK=1, seq=y, ack=x+1;
-
因为
Server建立连接后做出了响应,所以SYN=1, ACK=1
。因为
TCP规定SYN=1时不能携带数据,但要消耗一个序号, 所以
Server随机选取一个初始序号seq=y
。又因为
Server到 x为止的所有数据都已正确收到了,且Server告诉Client:我期待你下次给我发送包的初始序号(seq)是x+1,所以ack=x+1
。
- 发送后服务器进入syn_rcvd,表示服务器已经收到Client的连接请求,等待Client的确认。
(3)Client收到确认后还需再次发送确认,同时携带要发送给Server的数据:ACK=1, seq=x+1, ack= y+1;连接建立
-
因为
有 响应 动作,所以ACK=1
(因为要携带发送的数据,所以这儿没SYN什么事)。因为(2)
中Server 已经告诉了这次它想收到包的初始序列号是x+1,所以初始序号为seq=x+1
。又因为
Client到 y为止的所有数据都已正确收到了,准备接收序列号为y+1的包,所以ack=y+1
。
- Server收到后,这个TCP连接就进入Established状态,就可以发起http请求了。
形象些:
- 第一次握手,由浏览器发起,告诉服务器我要发送请求了
- 第二次握手,由服务器发起,告诉浏览器我准备接受了,你赶紧发送吧
- 第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧
为什么需要三次握手,两次不行吗?
其实这是由TCP的自身特点可靠传输决定的。客户端和服务端要进行可靠传输,那么就需要确认双方
的接收和发送能力
,不然容易出现丢包的现象
- 第一次握手: 可以确认客服端的发送能力
- 第二次握手: 可以确认服务端的接收能力 和 发送能力
- 第三次握手: 可以确认客户端的接收能力。
3、为什么不能改成两次握手?
试想如果是用两次握手,则会出现下面这种情况:
如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。
4、三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的
。但是,第一次、第二次握手不可以携带数据
。
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTAB-LISHED
状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
文章Git地址:TCP三次握手
以上便是全部,如有解释不对的地方望及时指出~