浅析TCP三次握手及四次挥手
1. 三次握手
1. TCP为什么相较于UDP是可靠连接?
可靠连接是指,待通信的两个实体,能够满足通信数据包的有序性、完整性以及可靠性。对于UDP来说, 它的连接过程不需要握手,忽略丢失的数据包,并且不需要维持通信双方在线(即服务器端不需要维持巨大的并发连接)。而TCP在传递数据之前,会经历三次握手来确保通信的两个实体均处于ESTANLISHED状态, 另外还采用校验和、序列号、确认应答、超时重传、拥塞控制、拥塞避免等控制方法,以此来确保数据的可靠传输。
2. 三次握手的本质
三次握手的本质在于确保通信双方收到彼此请求/接收通信的确认消息
这里我们以电话拨号到通话为例,假设A给B通电话,那么其过程如下:
A. 拨号,(请求与B通话)
B. 拿起电话并接听,“喂!您哪位?”,(希望确认A的身份)
A. 收到对方询问身份, 并回复“我是A啊”, (回传身份确认消息)
B. 收到回复,并确认了A的身份, 开始尬聊
3. 三次握手的过程
第一次握手:客户端主动请求建立连接。 客户端发送连接请求报文段, 将SYN首部标志位置为1, Seq(Sequence Number)为X(由操作系统动态随机选取一个32位长(8字节)的系列号。随后客户端进入SYN_SEND状态,并等待服务器端的确认。
第二次握手:服务器收到客户端SYN请求,并发送被动连接请求。服务器收到第一次握手过程中接收的SYN,需要向客户端发送一个确认号ACK(收到的Seq序列号长度自增1),此外,还需将被动请求连接请求发送给客户端,及SYN=1, 最后再从操作系统随机分配一个8字节长度的序列号用于填充Seq,将以上信息发送给客户端之后,服务器端便进入SYN_RECV状态。等待来自客户端的响应请求确认。
第三次握手:客户端收到服务器的被动连接请求,并发送确认号。客户端收到SYN&Seq&ACK之后,发送确认请求,ACK为接收的Seq序列号自增1,Seq为接收的ACK确认号。至此TCP便完成了三次握手。
4. 为什么是3次握手,而不是2次或者4次?
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是
“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。
在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。
这两种不同的表述其实阐明的是同一个问题。
谢希仁版《计算机网络》中的例子是这样的,
“已失效的连接请求报文段”的产生在这样一种情况下:
client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,
以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。
但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。
于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。
由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。
但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
采用“三次握手”的办法可以防止上述现象发生。
例如刚才那种情况,client不会向server的确认发出确认。
server由于收不到确认,就知道client并没有要求建立连接。”
我们也可以假想一下,如果是两次握手,那么客户端向服务端发送请求连接SYN这是第一次握手,服务器向客户端发送确认收到SYN的请求这是第二次握手,此时问题就来了,结果就是只要服务器发送一个确认报文给客户端,那么就代表连接建立了,但是网络信道是不可靠的,很容易碰到高时延的情况发生,假设一个来自客户端本就失效的连接报文(SYN)经过很长时间到达了服务器端(客户端早已断开连接),此时服务器按照流程返回一个确认号,便进入了ESTABLISHED状态,这样一来服务器状态与客户端状态便不一致了,假设有多个这样的情况发生,操作系统内存很容易崩溃。
说完了两次,那么四次呢? 四次握手其实是可以的。其与三次握手的相同之处在于,必须收到彼此的对应请求报文的确认号才进入ESTABLISHED状态。但是,四次握手不必要,他将第二次握手的ACK与SYN分两次进行发送了,其结果就是连接速度效率低。
因此采用建立TCP连接三次握手是必要的。
2.四次挥手
1. 四次挥手过程
四次挥手不存在Client及Server的说法, 因为客户端及服务器都能够主动关闭连接。
第一次挥手:主动方主动提出关闭连接。当主动方发送断开连接请求(FIN=1, Seq=X)给被动方之后, 主动方由ESTABLISHED状态转为FIN-WAIT-1状态等待来自服务器的确认消息。
第二次挥手:被动方收到来自主动方的FIN请求,被动方关闭应用层的应用程序,响应一个确认报文(ACK=x+1, Seq=y),并进入CLOSE-WAIT状态。
第三次挥手:被动方发送被动断开连接请求给主动方。但此时可能出现应用程序有些TCP消息已经存在于被动方的发送队列中,这部分数据仍能参与传送,所以等到数据发送完毕之后,被动方才发送被动断开连接请求(FIN=1, Seq=m,ACK=x+1), 并等待主动方确认,进入LAST-ACK状态。
第四次挥手:主动方接收到被动方发送来的被动断开连接请求, 主动方发送确认(ACK=m+1, seq=x+1),注意第四次挥手的Seq字段为第二次挥手的ACK字段的值。
2. 为什么连接的时候是3次,握手就是四次呢?
这是因为在第二次挥手的时候, 被动方接收到来自主动方的主动断开连接请求,随即进入CLOSE-WAIT状态,为什么会存在这一个状态呢?是因为TCP通信过程中,其发送窗口仍存在该应用程序待发送的数据报文,必须等待这些报文全部发送完毕之后,才能够发送被动断开连接请求。所以将FIN及ACK分两次进行。
3. 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
(补充:2MSL为最大报文段生存时间,代表发送到接收的最大时间)网络信道是不可靠的,随时都有可能发生请求超时的情况,假设第四次握手时,主动方发送的ACK确认报文丢失或超时,那么被动方由于不能收到该确认报文, 它就会又发送一个第三次握手的被动断开连接报文(FIN=1........),此时在TIME_WAIT状态下,主动方收到被动方的FIN请求,便开始重传ACK报文给被动方。因此,TIME-WAIT的意义就在于出现确认报文丢包时,能够重传确认报文。