Linux入门DAY35(TCP粘包问题与HTTP)

#Linux #TCP 粘包 #HTTP

前言

TCP 是面向字节流的可靠传输协议,字节流没有数据包边界,由此引出开发高频踩坑点:TCP 粘包。而 HTTP 是构建在 TCP 之上最常用的应用层协议,裸 Socket 手写 HTTP 客户端必须理解报文格式。

一、TCP 粘包

1.1 什么是粘包

TCP 是面向字节流协议 ,不存在数据包边界。发送的数据会存放在内核 Socket 缓冲区。 发送端发送速度快、接收端处理慢,多个独立数据包在内核缓冲区缓存合并;应用层调用recv()读取时,一次读到多份原始数据包,数据包粘连在一起,无法区分原始报文边界,该现象就是TCP 粘包

⚠️ UDP 不会发生粘包,UDP 面向数据报,一次recvfrom读取一个完整数据报。

1.2 粘包产生两种场景

  1. 发送方造成:内核 Nagle 算法将多个小数据包合并,一次性发送出去。
  2. 接收方造成:接收缓冲区积攒多份发送过来的数据,应用程序一次 recv 读出全部。

粘包不是 bug,不是 TCP 协议故障 ,是字节流特性带来的应用层问题,必须在应用层设计协议解决

1.3 TCP 粘包三种工程解决方案

方案 1:固定长度收发

每次收发固定大小的数据,例如直接收发结构体。发送send(sockfd, &data, sizeof(struct data),0);,接收固定sizeof(struct data)字节。

缺点:数据不足时需要填充占位;跨平台注意大小端、结构体对齐问题。

方案 2:特殊分隔符分割报文

数据包末尾添加专属分隔符(如\n0x7E)。接收方循环读数据,在缓冲区查找分隔符,切割拆分出完整报文。

缺点:业务数据内部不能出现分隔符字符,否则解析错乱。

方案 3:自定义帧协议(工业项目最常用)

自定义帧格式:帧头 + 数据长度 + 消息体 + 校验 + 帧尾。 接收逻辑:

  1. 先读取帧头;
  2. 读取消息长度字段;
  3. 根据长度读取对应字节数的消息体;
  4. 校验校验和,完成一帧解析。

核心思路:提前告知接收方本次数据包到底多大,不受 TCP 字节流粘连影响。

二、HTTP 协议

HTTP 属于应用层协议,底层基于 TCP。

  • HTTP 默认端口:80(明文)
  • HTTPS 默认端口:443(TCP+TLS 加密,裸 socket 不能直接发送明文 HTTP)

2.1 HTTP 工作流程

  1. 客户端与服务器建立 TCP 三次握手连接
  2. 客户端向服务端发送HTTP 请求报文
  3. 服务端处理请求,返回HTTP 响应报文
  4. 根据Connection字段决定断开连接还是保持长连接
    • Connection: close:短连接,请求完成立刻断开 TCP
    • Connection: keep‑alive:长连接,连接复用,一段时间内保持连接可以继续传输数据

2.2 HTTP 请求报文格式

文本格式,由 4 部分组成:请求行、请求头、空行\r\n\r\n、请求体。

复制代码
GET / HTTP/1.1\r\n
Host: www.baidu.com\r\n
User‑Agent: Mozilla/5.0 xxx\r\n
Accept: */*\r\n
Connection: close\r\n
\r\n
  • 请求行:方法 资源路径 HTTP版本GET 后面必须有空格,写错服务器返回 400。
  • 常用方法:GET查询资源、POST提交数据、HEAD只获取响应头、PUT修改、DELETE删除。
  • 空行\r\n\r\n代表请求头结束,如果缺少会导致服务器一直等待剩余数据。

2.3 HTTP 响应报文格式

响应行、响应头、空行、响应体 (html/json 等数据)

复制代码
HTTP/1.1 200 OK\r\n
Content‑Type: text/html;charset=utf‑8\r\n
Server: openresty\r\n
\r\n
<!DOCTYPE html><html>......

2.4 HTTP 状态码

三位数字,分为 5 大类:

  1. 1xx 信息提示:请求已接收,继续处理
  2. 2xx 请求成功200 OK正常访问成功
  3. 3xx 重定向:资源位置跳转
  4. 4xx 客户端错误
    • 400 Bad Request 请求语法错误(GET 缺少空格经常出现)
    • 404 Not Found 找不到访问资源
  5. 5xx 服务端错误:服务器内部异常

重要踩坑:访问 HTTPS (443),不能直接裸 TCP socket 发送明文 HTTP 报文;443 端口需要完成 TLS 握手,需要 openssl 库。

小结

  1. TCP 粘包根源:TCP 是字节流,无报文边界;属于应用层问题,TCP 本身没有错误。三种解决方式:定长、分隔符、带长度自定义帧协议。UDP 无粘包。
  2. HTTP 基于 TCP;80 明文、443 加密;报文严格遵循\r\n换行,空行分割头部与数据;状态码定位请求故障;443 端口不能直接裸 TCP 发送 http 明文。
相关推荐
好评12417 分钟前
【Linux】传输层协议TCP
linux·网络·tcp/ip
Shell运维手记23 分钟前
Linux mdadm 软 RAID + LVM 完整综合笔记
linux·运维·笔记·5g
凤舞飘伶34 分钟前
服务器内存满日常运维命令
linux·运维·服务器
Fcy6481 小时前
Linux下 Socket编程 —— TCP网络编程
linux·网络·tcp/ip
ouynagda1 小时前
HTTP协议与Socket网络编程笔记
网络·笔记·http
LongRunning2 小时前
【Linux】RK3568(三)操作-视频流
linux
Discipline~Hai2 小时前
Linux网络编程02-TCP协议
linux·网络·tcp/ip·嵌入式·linux网络编程
abc light3 小时前
Linux TCP网络
linux·网络·tcp/ip
OPEN-F3 小时前
C++综合实战:网络编程入门与HTTP客户端
网络·c++·http