谈谈TCP三次握手和四次挥手

三次握手:

  • 第一次 
    A发送连接请求报文段。首部中的同步位SYN=1,同时选择一个初始序号seq number=x。此时A进入SYN_SENT状态。 

  • 解析:SYN=1,ACK=0,表示这是一个请求连接的包,seq number表示发包数据字节序号,由于下层的IP层可能会对TCP的数据拆包,因此IP层会对每个字节编号,但是这是建立连接期间,根本没有数据,发送只是只有首部的空包,因此seq number 是一个随机数,这个随机数是有用处的,用来作为认证标记。
  • 第二次 
    B收到连接请求报文段后,如果同意建立连接,则向A发送确认。 
    在确认报文段中把SYN和ACK都置1,确认号ack number为x+1,同时自己也要喧杂一个初始序号seq number= y。B进入到SYN_RCVD状态;

  • 解析:SYN=1,ACK=1,表示这是一个接受连接的包,seq number=y(同理y也是一个随机数),ack number=x+1,ack number 表示期望下一次接受到的包的起始序号,尽管没有收到应用数据,但是TCP规定,一次连接请求包(包中包含SYN或FIN标志位好像都要)要消耗一个seq number,因此ack number=x+1,必须等于x+1。
  • 第三次 
    A收到B的SYN+ACK包,检查ack number是否正确,即是否等于x+1,(正确才证明服务器正确收到自己的消息,能够听到自己的消息)以及状态码ACK是否为1,若正确还要向B发出确认,ACK置1,确认号ack number=y+1,自己的序号seq number为x+1。 
    此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

 

seq是***,这是为了连接以后传送数据用的,ack是对收到的数据包的确认,值是等待接收的数据包的***。
在第一次消息发送中,A随机选取一个***作为自己的初始序号发送给B;第二次消息B使用ack对A的数据包进行确认,因为已经收到了***为x的数据包,准备接收***为x+1的包,(第一次消息是空值,所以只加1)所以ack=x+1,同时B告诉A自己的初始***,就是seq=y;第三条消息A告诉B收到了B的确认消息并准备建立连接,A自己此条消息的***是x+1,所以seq=x+1,而ack=y+1是表示A正准备接收B***为y+1的数据包。

seq是数据包本身的***;ack是期望对方继续发送的那个数据包的***。

 

ACK=1时,ack才有效

seq***就是一个标志,代表这段数据的长度有多少到多少,ack回应就是告诉对方我收到了多少多少数据。比如A发送seq=1000,长度有100,B收到后,返回的ack就是1100,代表希望下次A从1100发送。上面的第二次为什么ack等于x+1,就是因为是空数据,但是一次连接请求包要消耗一个seq number(如果不是包中包含SYN或FIN标志位的话应该是不用+1的,空数据的话),因此ack number=x+1,必须等于x+1。然后A又会检查是否x+1,是的话才证明B收到消息了才返回的消息(个人理解)

 

 

为什么要三次握手? 
也就是为什么Client还要发出一次确认呢?主要是防止已失效的连接请求突然又传送到了Server。比如说Client发出了一个连接请求,但是这个请求报文在某些网络节点滞留了,这时Client会再发出一个连接请求,从而建立连接、数据传输然后释放连接。但是那个滞留的请求报文可能在某个时间到达了Server,Server误以为这时Client又发出一次新的连接请求,于是就向Client发出了确认报文,同意建立连接。 
假设不采用三次握手,那么只要Server发出确认就会建立新的连接。但是由于Client此时并没有真的发出建立连接的请求,因此不会理睬Server的确认也不会向其发送数据,但Server却认为新的连接已经建立了并一直等待Client发来数据,此时Server的很多数据就这么浪费了。

采用三次握手的话可以防止上面现象的发生,例如在刚才的情况下Client不会向Server发出确认,Server由于收不到确认就知道Client没有要求建立连接,就不会傻傻等着了。

 

四次挥手:

谈谈TCP三次握手和四次挥手

四次挥手:

  • A首先发出连接释放报文段,并停止发送数据,主动关闭TCP连接。 
    A将FIN置1,其序号seq = u,等于前面已传送过的数据的最后一个字节的序号加1,此时A进入FIN_WAIT_1状态。

  • B收到连接释放报文后即发出确认,ACK置1,确认号ack=u+1,而这个报文段自己的序号是v,等于前面已传送过的数据的最后一个字节的序号加1。然后B进入到CLOSE_WAIT状态。

  • 这时从A到B这个方向的连接就释放了,TCP连接处于半关闭状态,即A已经没有数据要发送了,但若B还要发送数据,A仍要接收。

  • A在收到B的确认后,就进入到FIN_WAIT_2状态。

  • 若B已经没有要发送的数据了,就发送连接释放报文。FIN置1,序号seq为w,B还必须要重复上次已发送过的确认号ack=u+1。此时B进入LAST_ACK状态。

  • A收到B的连接释放报文后,要对此发出确认,ACK置1,确认号ack = w+1,自己的序号为seq = u+1。 
    然后会进入TIME_WAIT状态。现在TCP连接还没有被释放掉,必须经过时间等待计时器设置的时间2MSL后A才进入CLOSED状态。MSL为最长报文段寿命,一般为2分钟。(B在收到A的这个报文后closed,但是A担心B收不到,B收不到就会重传FIN那个报文,所以A要等一会,如果B一直没声音,证明B收到了最后这个报文,否则B肯定会重传FIN)

为什么Client必须要等到2MSL时间呢?有两个原因:

  • 为了保证Client最后发出的ACK报文能够到达Server。 
    这个ACK报文段可能丢失,此时Server收不到确认就会超时重传之前的FIN报文段,Client就可以在2MSL时间内收到这个重传的FIN报文,从而重传一次ACK确认,重新启动2MSL。 
    如果Client不在TIME_WAIT状态等待一段时间而是在发送完ACK后立即关闭连接,那么就无法收到Server重传的FIN报文段,Server就不会按正常步骤进入CLOSED状态。

  • 防止“已失效的连接请求报文段”出现。 
    和三次握手中防止的已失效的连接请求报文段的情况相同,Client在发送完最后一个ACK后,再经过2MSL时间,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

相关文章:

  • 2021-11-10
  • 2021-09-01
  • 2021-10-21
  • 2021-07-29
  • 2021-09-23
  • 2021-09-21
  • 2021-06-13
猜你喜欢
  • 2021-06-19
  • 2021-08-19
  • 2021-07-19
  • 2021-06-08
  • 2021-09-17
  • 2021-09-04
相关资源
相似解决方案