WireShark分析:三次握手(为什么不采用两次握手),四次挥手(为什么不采用三次挥手)

版权声明:转载请标明附带连接标明出处 https://blog.csdn.net/Hollake/article/details/89356603
  • Tcp包的具体结构

与三次握手相关的变量为序号Sequence number(Seq),确认号Acknowledgment number(Ack),以及标志位(Flags)中的ACK,SYN两个变量,四次挥手还多一个FIN变量。注意:确认号Ack与标志位中ACK意义不同,标志位中的ACK表示确认序号有效。

 三次握手具体过程如下:

  1. 第一次握手,客户端发送SYN=1,以及客户端的初始序列号seq = x,tcp报文不携带数据,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。在第一次报文发送前服务器一直处于LISTEN状态。

  2. 第二次握手,服务器端在接收到客户端的SYN=1的握手请求后,如果同意连接,则向客户端发出报文。报文应包括SYN=1,ACK=1,Seq = y,Ack = x +1,这里的y表示服务器端自己初始化的序列号,这个报文同样不能携带数据。此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。

  3. 第三次握手,客户端在接收到服务器返回的确认接收的信息后,发出报文给服务器再次确认,表示接收到服务器的确定接收请求,报文中应该包含ACK = 1,Seq = x + 1,Ack = y +1。ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。

  • 这里再次强调,ACK为标志位中的确认序号,1表示有效,0表示无效。Ack表示确认号。


  •  下面通过Wireshark抓包进行分析

下图通过访问www.baidu.com,通过Wireshark抓包后通过对端口的过滤,得到下图。绿色框表示tcp的三次握手。其实在用Wireshark打开后就可以看到,绿色框的Info记录三次握手的第一个包为[SYN],第二个包为[SYN,ACK],第三个包为[ACK],这就表示tcp三次握手已经完成。

  • 接下来我们一个一个分析每个数据包的详细信息,首先来看第一个:可以看出标志位中的SYN = 1,客户端初始化序列号Seq = x =  0

  • 第二个包,第二次握手,也就是服务器端收到客户端连接请求后,同意连接,并发送报文给客户端,报文中可以看出服务器将自己的序列号初始化为Seq = y = 0,其实不止服务器的序列号不为0,客户端发送连接请求的三次握手中的第一次握手也不为0,只是Wireshark显示的相对序列号,如果想要关闭相对序列号/确认号,可以选择Wireshark菜单栏中的 Edit -> Preferences ->protocols ->TCP,去掉Relative sequence number后面勾选框中的√即可。从绿色框标出的数据可知,Seq的真实数据其实为9d 2d 44 8c 共4字节,32bit,所以序列号的范围为[0,2的32次方-1]。SYN = 1,ACK = 1,而确认序列号Ack = x + 1 = 1。

  • 第三个包,第三次握手,客户端接收到服务器端的确认信息后,继续发送表示已经收到服务器端确认信息的报文给服务器。从下图可以看出,ACK = 1,Seq = x + 1 = 1,Ack = y  + 1 = 1。至此三次握手就已经结束。

现在分析一下那么为什要进行三次握手呢,两次不行吗?

主要是为了防止已失效连接突然传送到服务器,导致发生错误或者建立连接造成资源浪费。

正常情况下,客户端A发出连接请求,但是因为连接报文请求丢失而未收到确认,于是A再重传一次连接请求,服务器B收到了A的第二次重传请求,B返回确认信息给A,A二次握手也确认了B的确认信息,建立连接完成,数据传输完成后,服务器B和客户端A断开连接。这种情况是客户端A的第一个连接请求丢失,第二个成功到达服务器B,两次握手,数据传输完成,最后断开连接。

异常情况下,客户端A第一次发送的连接请求在网路中可能在某个节点滞留时间比较长,但是没有丢失,最终到达了服务器B,这个时候服务器B以为这是一个新的客户端请求,便会发送确认报文到客户端A,建立连接,等待通信,但是此时客户端A实际并没有发送连接请求,服务器B一直等待A发送数据,但是A不会发送任何数据给B,这就一个已失效报文请求造成了服务器的资源浪费。采用三次握手就可以避免此问题的发生,一个客户端A的已失效请求连接报文发送到B,B回复确认连接报文,由于A没有实际的连接请求,所以A不会对B回复的确认报文进行确认,也就是不会进行第三次握手,B收不到第三次握手报文,那么B就不会建立连接,白白浪费资源。

那么四次握手行不行呢?四次握手显得就太多余了,例如A和B打电话:

A:你能听到我吗

B:我能听到你,你能听到我吗

A:我可以听到,你能听到我吗

B:......不想和沙雕说话

二次握手如下:

A:你能听到我吗

B:我能听到你,你能听到我吗

A:喂,你能不能听到啊?,你到底能不能听到说句话啊

三次握手如下:

A:你能听到我吗

B:我能听到你,你能听到我吗

A:我可以听到,有什么事儿你说吧


四次挥手

数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。

  1.  客户端主动关闭进程,发送连接释放报文,并停止发送数据,释放报文中FIN = 1,序列号 Seq = u。此时客户端进入FIN-WAIT-1状态,消耗一个序列号,报文不携带数据。
  2. 服务器收到客户端的释放报文后,发出确认报文,ACK = 1,序列号Seq = v,Ack = u + 1。此时服务器进入到CLOSE-WAIT状态,消耗一个序列号,报文不携带数据。此时客户端向服务器的连接已经释放,而服务器到客户端的连接还没有释放,这时候处于半关闭状态。服务器仍然可以向客户端发送数据,服务器端也会接受数据,这个状态会一直持续整个CLOSE-WAIT。
  3. 在服务器CLOSE-WAIT状态结束时,也就是数据传输完成,客户端收到服务器发送完成的确认报文,FIN = 1,ACK = 1,Seq = w , Ack = u + 1。
  4. 客户端发送确认信号ACK = 1,Seq = u +1 ,Ack = w + 1,客户端进入TIME-WAIT状态,服务器端接收到确认信号后关闭服务器到客户端的连接。在等待2MSL时间后,彻底关闭客户端到服务器的连接,不再接受任何数据。

 为什么客户端最后还要等待2MSL?

  主要有以下两个理由:

  1. 防止客户端最后一个ACK丢失,不能顺利到达服务器,因为这个报文可能会在网络中丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的ACK确认报文。因为客户端必须确认服务器已经收到确认报文ACK,如果服务器没有收到ACK,服务器会超时重传这个FIN-ACK,客户端一定可以在2MLS时间内收到FIN-ACK,接着客户端再重传一次ACK,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
  2. 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

      注解:MSL 是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。RFC 793中规定了MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。
 

为什么建立连接是三次握手,而释放连接是四次挥手呢?

       因为在连接时,服务器收到客户端的SYN连接请求后,可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送而关闭连接时,服务器收到对方的FIN报文时,仅仅表示客户端不再发送数据了但是还能接收数据,而服务器也未必全部数据都发送给客户端了,所以服务器可以立即关闭,也可以发送一些数据给客户端后,再发送FIN报文给客户端来表示同意现在关闭连接,因此,服务器的ACK和FIN一般都会分开发送,从而导致多了一次。

​​​​​​

参考文献

[1]https://blog.csdn.net/qzcsu/article/details/72861891

[2]https://uule.iteye.com/blog/2213562

[3]https://blog.csdn.net/sinat_35297665/article/details/80979181

猜你喜欢

转载自blog.csdn.net/Hollake/article/details/89356603