网络3️⃣TCP-流协议理解

1、TCP 和 UDP

TCP 是面向字节流的协议,UDP 是面向数据报的协议。

原因发送方操作系统对 TCP 和 UDP 协议的处理机制不同。

  • UDP:每个数据包(报文)对应一个完整的用户消息(照样发送)。
  • TCP把数据当作一连串无结构的字节流,以 MSS 为单位进行分段。
    • TCP 有一个缓冲区,数据太多时分段后再发送。
    • 数据太少时,可以积累足够多的字节再发送。

1.1、UDP 面向数据报

当应用层消息通过 UDP 传输时

  • 发送方

    • 操作系统不会对消息进行拆分组装好 UDP 首部后就交给网络层处理
    • 发出的 UDP 报文中的数据部分 = 完整的用户消息( i.e. 每个 UDP 报文就是一个用户消息的边界)。
  • 接收方

    • 接收到 UDP 报文后放入队列,每个队列元素都是一个 UDP 报文。

    • 应用程序调用 recvfrom() 时从队列中取出数据,从内核中拷贝到用户缓冲区。

    • 读一个 UDP 报文就能读取到完整的用户消息。

      图片

1.2、TCP 面向字节流

当应用层消息通过 TCP 传输时

  • 发送方
    • 消息可能会被操作系统分段(i.e. 以 MMS 为单位,分成多个 TCP 段)。
    • 完整的用户消息 = 一个或多个 TCP 段的数据部分(因此,TCP 是面向字节流)。
  • 接收方:假如应用程序不知道消息长度,则无法得知消息边界,无法读取到有效的消息
    • 一条用户消息可能被分到不同的 TCP 段。
    • 两条消息的部分数据也可能分到同一条 TCP 段(aka. 粘包)。

解释

2、TCP 粘包

粘包:两条消息的部分数据被分到同一条 TCP 段。

而接收方不知道消息边界,从而无法获得有效的用户消息。

解决方案:由应用层解决。

  1. 固定消息长度:固定每个用户消息的长度。

    • 当接收方收到规定的字节数后,就认为是完整且有效的消息
    • 简单,但灵活性不高。
  2. 特殊字符作为边界:在两条用户消息之间插入特殊字符。

    • 当接收方读取到特殊字符时,就认为已经读完一个完整且有效的消息
    • 注意:假如消息内容中出现了约定的特殊字符,需要进行转义,避免解析错误。
    • HTTP 的首部和正文就是通过回车换行符(CRLF)进行划分。
  3. 自定义消息结构:自定义一个消息结构,由包头和数据组成。

    • 包头:固定大小,且有一个字段说明数据长度。

    • 当接收方接收到大小固定的包头时,解析包头内容以获取数据长度,之后读取相应长度的数据以获得完整的消息

      // 示例
      struct { 
          u_int32_t message_length; 
          char message_data[]; 
      } message;
      
posted @ 2023-07-06 01:48  Jaywee  阅读(78)  评论(0编辑  收藏  举报

👇