Skip to content

TCP协议

TCP 协议灵魂 12 问,巩固你的网路底层基础!-腾讯云开发者社区-腾讯云

image.png

TCP和UDP的区别

  • 面向连接

    • TCP 需要客户端与服务端之间通过三次握手建联,之后才可以发送数据。
    • UDP直接向服务端发数据包。
  • 可靠性

    • 有状态
      • TCP发数据包时,保证数据包按顺序到达。
    • 可控制
      • 当TCP协议丢包时,可以控制重发和自己的发送速度,保证数据包完整和有序。
    • UDP 是无状态并且不可控的。
  • 基于字节流

    • TCP将数据包通过字节流发送。
    • UDP数据传送直接发送数据报。

    用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的(粘包问题)。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。

三次握手

TCP三次握手的目的是为了确认客户端和服务端双方都具备 发送数据和接受数据 的能力。

SYN-ACK应答机制

TCP 协议中,客户端与服务端建联用到了 SYN-ACK 应答机制。

  • SYN

    SYN 是发起连接标志,表示要建立链接。

  • ACK

    ACK是确认标识,确认连接的正确性。

    服务端收到客户端发送的 SYN 标志后,将ACK发给客户端,以表示消息确认建立链接。只有第二次握手和第三次握手才会有 ACK 标志。

  • seq

    用来标识从TCP发端向TCP收端发送的数据字节流。是一个初始序号。

  • ack

    确认序号。当 ACK 标志存在的时候,ack 确认序号为 seq +1;

    • 通俗来说,就是 服务端收到消息后,根据 seq + 1 作为 ack 传给客户端。客户端通过计算 ack 发现和上次发的 seq 值一致,代表通信成功。
    • 接下来第三次握手的时候,客户端同样会发一个 ack 给服务端。

三次握手流程

  1. CLOSED:这是TCP连接的初始状态,表示连接是“关闭”或“未打开”的。
  2. LISTEN:当服务器端的某个端口处于监听状态,等待客户端连接的到来时,处于此状态。
  3. SYN_SENT:客户端发送SYN请求建立连接后,处于此状态,等待服务器发送SYN+ACK。
  4. SYN_RCVD:服务器收到来自客户端的连接请求SYN之后,处于此状态,在接收到SYN请求之后会向客户端回复一个SYN+ACK的确认报文。
  5. ESTABLISHED:当客户端回复服务器一个ACK和服务器收到该ACK(TCP最后一次握手)之后,服务器和客户端都处于该状态,表示TCP连接已经成功建立。

image.png

  • 第一次握手

    确认了客户端的发送能力。

  • 第二次握手

    确认了服务端的接收能力和发送能力。

  • 第三次握手

    确认了客户端的接收能力。

为什么握手是三次,不能是两次或者四次吗

四次握手

三次握手就能确认客户端和服务端的接收和发送能力,再进行握手是没有必要的。

两次握手

没有第三次握手会导致服务端不知道客户端是否能正常接收数据。

  • 假如第二次握手失败

    对服务端来说,并不知道客户端是否建立连接。

    对客户端来说,不能成功建立连接,因为服务端的第二次握手没有成功。

    image.png

  • 假如客户端第一次握手延时重发

    对于服务端来说,收到了两次第一次握手,发出两次第二次握手。

    对于客户端来说,两次第一次握手都是一次TCP请求,属于重发。但是服务端返回两个第二次握手,会导致第二次握手出错一次(浪费资源)。

    image.png

三次握手过程可以携带数据吗

image.png

在第三次握手时,可以携带数据。

因为第三次握手对于客户端来说,服务端接收和发送能力都是正常的,所以可以发送数据,相对安全。

但是第一次不可以,在接收发送能力不能确认的情况下,如果携带数据是存在隐患的。比如攻击服务器,多次建联携带大量数据,那么在第一次握手时服务器就会消耗资源处理数据。

四次挥手

https://blog.csdn.net/huaishu/article/details/93739446

image.png

image.png

可以看到四次挥手的过程

  • FIN、ACK

  • ACK

    服务端返回给客户端ACK之后,此时不接收客户端发来的数据。但是服务端可以把剩余数据发给客户端。

    等发送完毕之后,再通知客户端。

  • FIN、ACK

    客户端经过 MSL 时间后进入 CLOSED 状态。

  • ACK

    服务端收到之后进入 CLOSED 状态,即断开连接。

为什么需要四次挥手

TCP是全双工的连接,必须两端同时关闭连接,才算真正结束。

  • 当一方主动 close的时候,它准备关闭写。但是还可以接收另一方发送的数据。
  • 发送 FIN 结束报文给另一方,另一方会先回ACK确认收到了结束报文。
  • 另一方将数据全部返回之后,发送 FIN 报文,表示可以关闭。
  • 最后主动关闭一方收到 FIN 结束报文之后,发送 ACK给另一方。即两端可以都关闭。

TCP报文格式

TCP报文

image.png

  • 源端口号和目的端口号是必须的,不然数据不知道发向服务端的哪个应用。

    源端端口,一般是随机端口。而目的端是确定的端口,与应用绑定。

  • 包的序号,是为了解决包乱序的问题。

  • 确认序列,是为了确认包发出去后,目的端是否收到包,如果没收到应该重新发送。确认序列是为了解决丢包的问题。

  • 状态位。

    TCP是面向连接的,需要维护双方的状态。包里面包含了状态位,能对客户端和服务端的状态进行变更。

    TCP在传输数据之前,要进行三次握手建立连接。

    • SYN - 发起连接
    • ACK - 回复
    • FIN - 结束连接
    • RST - 重新连接
  • 窗口大小

    • TCP 要做流量控制,通信双方在包中声明窗口大小(缓存大小),标识当前自身的处理能力。防止数据过多处理不过来。

    TCP 还可以做拥塞控制,在出现网络通道堵塞时,能控制自己发送的速度。

    TCP网络包

    在建立连接之后,TCP报文由 HTTP报文+TCP头部组成,然后交给传输层下层的网络层去处理。

    其中 TCP 报文保证了 TCP的功能。

    • 目的端口号保证接收消息的应用。
    • 序号保证有序性。
    • 确认序列保证不会丢包,如果出现丢包就会重新发包。
    • 状态位保证连接状态。
    • 窗口大小保证了TCP的流量控制,防止数据过多无法处理。

    image.png

TCP三次握手

在 HTTP 传输数据之前,需要进行 TCP建连,这个建连其实就是维护一个状态位。

image.png

  • 一开始,客户端和服务端都处于 CLOSE 状态。

  • 服务端主动监听某个端口,状态为 LISTEN

  • 客户端主动发送消息,发送 SYN 标识请求连接。之后客户端处于SYN_SENT状态。

  • 服务端收到客户端的 SYN 标识后,向客户端发送想建立连接的 SYN 标识,同时发送确认连接的 ACK标识。

    之后服务端处于SYN_RCVD状态。

  • 客户端收到服务端发来的 SYNACK标识后,向服务端也发送一个 ACK 标识,使得服务端确认自己的发送能力。

    此时客户端已经证明了自己的发送和接受能力正常,因为他发消息和收消息都正常。

    状态变为ESTABLISHED,表示TCP连接成功

  • 服务端收到客户端发来的 ACK标识后,确保自己接收和发送能力都正常,状态变为 ESTABLISHED

SYN 标识代表发起连接,ACK标识代表确认连接正确性。

查看TCP连接状态

Plain Text netstat -napt

image.png

TCP数据分割

如果 HTTP 报文过长,为了保证数据发送可靠性。TCP会将报文分割发送,称为 Segment(段)。

image.png

  • MSS:一个网络包容纳的TCP数据的最大长度。

    传输层的分割,将TCP数据包分割为段。

    该分割规则在网络层。

  • MTU:一个网络包的最大长度,以太网中一般是 1500 字节。

TCP 数据包根据 MSS 进行分割,分割之后,每段都放进单独的网络包,加上TCP头部和IP头部等信息之后进行发送。

image.png

如何确定一个唯一的TCP连接

根据TCP四元组可以确认一个唯一的TCP连接。

  • 源IP
  • 源端口
  • 目的IP
  • 目的端口

image.png

源IP和目的IP的字段(32位)在IP头部,作用是通过 IP 协议找到指定主机。

源端口和目的端口在 TCP 头部,作用是告诉 TCP 协议报文发给主机的哪个进程。

可靠传输与超时重传

在TCP数据包传输过程中,可能出现丢包、错包、乱序等问题。

确认应答

TCP的通信流程中,接收方收到数据包后会返回一个 ACK,用来通知发送方已它已经接收到了数据。

而发送方在发完数据包之后就会等待这个 ACK,如果在规定时间内没有收到 ACK,就会触发重传机制

当接收方收到重传的数据时,它可以根据以下步骤进行处理:

  1. 识别重复报文段:接收方会检查重传数据包的序列号,并与已接收到的数据包序列号进行比较。如果序列号相同,说明这是一个重复的数据包。
  2. 丢弃重复报文段:由于TCP协议是面向连接的、可靠的传输协议,它保证数据按序到达接收方。因此,当接收方识别出重复的数据包时,它会直接丢弃这个数据包,不会将其传递给应用层处理。
  3. 发送ACK:尽管接收方已经丢弃了重复的数据包,但它仍然需要发送一个ACK给发送方,以确认已接收到的最后一个按序的数据包。这个ACK的确认号将是下一个期望接收的报文段的序列号。

滑动窗口

以滑动窗口方式进行流量控制

窗口大小表示服务端的接受能力,用来限制发送方的发送速度。

如果接收方有未确认的数据包,数据窗口不会滑动。直到确认报文收到或者触发了重传机制。

序号

TCP发包过程可能存在乱序得问题。

TCP为每个数据包分配了要给独立的序号,用来保证数据包的有序传输。

如果接收方检测到序号不连续的数据包,说明有丢包发生,就会要求发送方进行重传。