TCP握手挥手

  • TCP

    • TCP 是面向连接的、可靠的、基于字节流的传输层通信协议

      • 面向连接:一定是「一对一」才能连接,不能像 UDP 协议一个主机同时向多个主机发送消息
      • 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端
      • 字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序不知道「消息的边界」,无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃
    • TCP连接

      • 用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括 Socket、序列号和窗口大小称为连接
        • Socket:由 IP 地址和端口号组成
        • 序列号:用来解决乱序问题等
        • 窗口大小:用来做流量控制
    • TCP与UDP区别

      1. 连接

      • TCP 是面向连接的传输层协议,传输数据前先要建立连接。
      • UDP 是不需要连接,即刻传输数据。

      2. 服务对象

      • TCP 是一对一的两点服务,即一条连接只有两个端点。
      • UDP 支持一对一、一对多、多对多的交互通信

      3. 可靠性

      • TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。
      • UDP 是尽最大努力交付,不保证可靠交付数据。但是可以基于 UDP 传输协议实现一个可靠的传输协议,比如 QUIC 协议

      4. 拥塞控制、流量控制

      • TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
      • UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。

      5. 传输方式

      • TCP 是流式传输,没有边界,但保证顺序和可靠。
      • UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。

      6. 分片不同

      • TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
      • UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层
    • 传输层的「端口号」是为了区分同一个主机上不同应用程序的数据包 传输层两个传输协议 TCP 和 UDP,在内核中是两个完全独立的软件模块

      TCP和UDP可以使用同一个端口

  • TCP连接

    • TCP 是面向连接的协议,所以使用 TCP 前必须先建立连接,而建立连接是通过三次握手来进行的
      • 一开始,客户端和服务端都处于 CLOSE 状态。先是服务端主动监听某个端口,处于 LISTEN 状态
      • 客户端会随机初始化序号(client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN 标志位置为 1,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态
      • 服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1, 接着把 SYNACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态
      • 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于 ESTABLISHED 状态。
      • 服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态
    • 为什么三次握手?
      • 三次握手的首要原因是为了防止旧的重复连接初始化造成混乱
        • 两次握手,旧连接建立中,网络堵塞,又新发新连接,旧连接先到,导致服务器建立无效连接,浪费存储
        • 在两次握手的情况下,服务端没有中间状态给客户端来阻止历史连接,导致服务端可能建立一个历史连接,造成资源浪费