• TCP三次握手四次挥手


    本文从三次握手角度四次挥手来带你快速理解TCP

    TCP报文段

    在将三次握手之前,先来看看每次握手都发送了什么东西

    这里不对报文段作详细解释,只讲解下三次握手四次挥手有关的字段

    • 序号

      Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

    • 确认号

      Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

    • ACK:确认序号有效。占1位,值0/1。
    • SYN:发起一个新连接。占1位,值0/1。
    • FIN:释放一个连接。占1位,值0/1。

      四次挥手时用到,表明断开连接

    三次握手

    所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。

    最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。

    注意,三次握手握的是通信双方数据原点的序列号。

    再来看下什么是序号和确认号

    序号,确认号

    在开启TCP会话时,客户端和服务端都会给自己的数据编号,这就是序号/序列号,初始序列号是随机的,0~2^32之间。

    此时客户端待发送的数据首序号为1001,服雾端待发送数据首序号为2001。注:客户端和服务端序号系统是独立的

    1. 假设客户端发送的报文中,序号:1001,携带的数据为200
    2. 服务端成功接受到这200数据后,期望客户端下一次发送的数据是从1001+200开始的,发送给客户端的报文中序号为2001,确认号为1001+200,同时服务器也发送100数据
    3. 客户端收到服务端的确认号1201,验证无误,同时收到服务端100的数据,然后再向服务端发送300的数据,那么这300的数据序列号肯定是1201-1500,这时客户端发送给服务端的报文应为
    序列号:1201(要发送的数据首序号,同时也是服务器刚刚发来的确认号)
    确认号:2200(从服务器发来的报文中得知服务器发送的首序列号为2001,又因为服务端还携带了200的数据,所以确认号应为2201,告诉服务器下次发给我的数据应当从2201开始发送,但是发送多少我不管,服务端可以从2201判断出客户端成功收到了那200的数据)
    客户端发送给服务端那300的数据
    ...
    

    简而言之,序列号是自己的序列号,确认号
    是对方发来的包中的(序列号+数据长度),因为确认号是期望收到对方下一个报文的第一个数据字节的序号。

    第一次握手:客户端->服务端

    当某个主机开启一个TCP会话时,他的初始序列号是随机的,这里假定客户端初始序号为1000,服务端初始序号为2000

    TCP会话的每一端都包含一个32位(bit)的序列号,该序列号被用来跟踪该端发送的数据量。每一个包中都包含序列号,在接收端则通过确认号用来通知发送端数据成功接收

    所以在TCP报文段中:

    • 序号:X,如1000
    • ACK: 0 (不是应答报文)
    • SYN: 1 (表明发起一个新连接)

    因为这是第一个包,此时通话还未开始,没有通话的另一端需要确认,所以这个包中的确认号没有意义

    TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。

    第二次握手:服务端->客户端

    TCP服务器收到请求报文后,如果同意连接,则发出确认报文。

    报文段中

    • 序列号: seq=y,假设2000

      该初始序列号是随机的

    • 确认号: ack=x+1,1001 = 1000 + 1 (客户端消耗的那1个序号)
    • ACK=1
    • SYN=1

    同样,SYN=1,这个报文也不能携带数据,但是要消耗一个序号。

    第三次握手:客户端->服务端

    TCP客户进程收到确认后,还要向服务器给出确认

    确认报文:

    • 序号: seq=x+1 如1001 = 1000 + 1 (自身的序号在发送第一个包的时候被消耗了)
    • 确认号:ack=y+1 如2001 = 2000 + 1 (服务端应答包消耗的那1个序号)
    • SYN: 0
    • ACK: 1

    此时,TCP连接建立。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。

    四次挥手

    TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close() 操作即可产生挥手操作。

    第一次:客户端->服务端

    客户端发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1)

    发送完毕后,客户端进入 FIN_WAIT_1 状态。

    TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

    第二次:服务端->客户端

    服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

    第三次:服务端->客户端

    服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。

    发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。

    TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

    第四次:客户端->服务端

    客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。

    服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。

    注意此时TCP连接还没有释放,必须经过2*MSL(最长报文段寿命)的时间后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,当客户端撤销相应的TCB后,才进入CLOSED状态。
    服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。服务器结束TCP连接的时间要比客户端早一些。

    参考

    Blog

    TCP的三次握手与四次挥手(详解+动图)

  • 相关阅读:
    MATLAB批量读入图片
    MATLAB小技巧
    Ubuntu下OpenCV不能被某个python版本识别
    切换Ubuntu系统python默认版本的方法
    LoadRunner内部结构(2)
    LoadRunner例子:检查点为参数的一个例子
    LoadRunner中字符串的操作
    LoadRunner脚本实例来验证参数化的取值
    LoadRunner编程之文件的操作
    LoadRunner关联函数的脚本实例--如何操作关联参数
  • 原文地址:https://www.cnblogs.com/lifan1998/p/14326713.html
Copyright © 2020-2023  润新知