赞
踩
TCP
是面向连接的、可靠的、基于字节流的传输层通信协议。
TCP
是面向连接的协议,所以使用 TCP
前必须先建立连接,而建立连接是通过三次握手来进行的。
在讲解三次握手的过程之前,我们先来看一下 TCP
包的结构:
TCP
包头大小在大多数情况下是固定的,它通常是 20
字节(不包括任何选项),但如果启用了选项,则最多可以达到 60
字节。下面是 TCP
包头的一般结构:
TCP
包头的长度,以 4字节
为单位。因此,数据偏移的值乘以 4
就是 TCP
包头的总长度。这个字段也被称为 头部长度
。TCP
连接的状态,包括 SYN
、ACK
、FIN
、RST
、PSH
、URG
等。TCP
报文的完整性。URG
标志被设置时,紧急指针表示紧急数据的末尾位置。MSS
)、窗口缩放因子等,每个选项的大小不定。在三次握手过程中,我们主要关注序列号、确认号以及标志位中的SYN和ACK
通常来说,服务器会开放监听端口,而客户端则主动连接这个端口,创建连接的时候,会进行三次握手,过程如下图所示:
SYN
包到服务器,附上一个随机生成的序列号(ISN
)。此时客户端处于 SYN_SEND
状态。SYN+ACK
包到客户端,附上一个随机生成的序列号,确认号则是客户端上传的序列号+1。此时服务端处于SYN_RECV
状态。ACK
到服务器,确认号是服务器下发的序列号+1。此时客户端处于ESTABLISHED
状态,连接已建立,这个包可以顺带发一些数据。ACK
后,也进入ESTABLISHED
状态,可以收发数据。三次握手的一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number)
,以便让对方知道接下来接收数据的时候如何按序列号组装数据。同时也确保了服务端和客户端的收发都能正常进行。
使用 wireshark
抓包工具,我们可以看到三次握手的数据:
想像一个场景,客户端发了SYN
之后宕机了,重启后又发了新的SYN
。如果只有两次握手的话,当服务器收到旧的SYN
之后,发送ACK
给客户端,就直接进入ESTABLISHED
状态,这时候就可以发数据了。
但是客户端期待的是新的SYN
的序列号,发现服务端发的确认号不对应,会关闭这个连接,而服务器此时已经发了数据过来,这就造成了混乱。
而三次握手,客户端可以收到ACK
之后,判断确认号,正确则返回ACK
,错误则返回RST
告诉服务器关闭这个连接。
使用三次握手和RST
控制消息,将是否建立连接的最终控制权交给了客户端,因为只有客户端有足够的上下文来判断当前连接是否是错误的或者过期的,这也是TCP
使用三次握手建立连接的最主要原因。
TCP
协议的通信双方,都必须维护一个序列号,用来保证数据包的有序,以及丢包时能够重发,所以这个初始化的序列号是很重要的。当客户端发SYN
给服务器时,服务器需要返回ACK
确认,而服务器发SYN
给客户端时,客户端也需要发ACK
确认,才能确保两边都有正确的序列号。服务器在发SYN
和ACK
时,可以合并成一条消息发送,所以是不需要四次握手的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。