linu 网络 :TCP粘包及UDP

发布于:2025-08-30 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、TCP 粘包问题(续上一节)

1. 粘包本质

核心原因 具体表现
TCP 是字节流协议,无天然消息边界 发送端:多个小消息被合并成一个 TCP 段(Nagle 算法优化)
内核缓冲区(发送 / 接收)暂存数据 接收端:多个 TCP 段数据被合并,一次性交给应用层

2. 应用层解决思路

解决方案 核心逻辑 适用场景 优缺点
特殊字符边界 每个消息末尾加固定标记(如\r\n),接收端按标记拆分 文本类数据(如 HTTP 协议) 优点:实现简单;缺点:消息含标记时易误拆分
定长消息 约定固定消息长度(如 100 字节),不足补空,接收端按固定长度读取 数据长度固定场景(如传感器数据) 优点:逻辑简单;缺点:长度不固定时浪费带宽
自定义结构体协议 设计 “消息头 + 消息体”,头中含消息体长度(如type字段标识长度 / 类型) 复杂数据(文件、二进制数据) 优点:灵活无歧义;缺点:需两端协议兼容

二、TCP 编程(C/S 模型)

1. 核心 API 对比

API 类型 函数原型 关键差异 适用场景
标准 IO 函数 read(int fd, void *buf, size_t len)
write(int fd, const void *buf, size_t len)
无额外标志,仅支持阻塞 通用 IO 操作(含 socket)
Socket 专用函数 recv(int sockfd, void *buf, size_t len, int flags)
send(int sockfd, const void *buf, size_t len, int flags)
支持MSG_DONTWAIT(非阻塞) 需控制读写模式的 socket 场景

2. 客户端与服务器流程对比

角色 核心步骤 关键说明
TCP 客户端 1. socket():创建 TCP socket
2. (可选)bind():绑定客户端地址(通常系统自动分配)
3. connect():连接服务器(必须成功后通信)
4. send()/recv():数据交互(需处理粘包)
5. close():关闭 socket
依赖connect()建立连接,无连接则无法通信
TCP 服务器 1. socket():创建 TCP socket
2. bind():绑定固定端口(客户端需知道该端口)
3. listen():开启监听(设置监听队列长度)
4. accept():接收客户端连接(返回新通信 socket)
5. send()/recv():通过新 socket 交互
6. close():关闭通信 socket 和监听 socket
listenfd仅用于监听,connfd用于实际通信

3. 常见场景实现

场景 核心技术 注意事项
点对点聊天 多线程 / 多进程:
- 线程 1:读键盘→send()
- 线程 2:recv()→打印
线程需pthread_join()/pthread_detach()回收资源
文件传输 自定义结构体协议:
- 步骤 1:发文件名(type=-1
- 步骤 2:循环发文件数据(type=数据长度
- 步骤 3:发结束标志(type=0
需处理文件读写错误(如read()返回 0 表示文件结束)

三、UDP 编程核心(C/S 模型)

1. UDP 协议核心特点

特点 具体说明 影响
无连接 无需connect(),直接通过sendto()指定目标地址 通信灵活,但需每次发送时携带目标地址
不可靠 不保证数据送达、不保证顺序、不重传 适合实时场景(如视频),不适合需可靠传输的场景(如文件)
数据报 每个sendto()对应一个完整消息,recvfrom()一次读一个 无粘包问题,无需额外处理消息边界

2. 核心 API(sendto/recvfrom)

函数 原型 关键参数说明
sendto ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) dest_addr:目标地址(客户端→服务器需填服务器地址)
recvfrom ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) src_addr:保存发送方地址;addrlen需先初始化(值结果参数)

3. 客户端与服务器流程对比

角色 核心步骤 关键说明
UDP 客户端 1. socket():创建 UDP socket
2. (可选)bind():绑定客户端地址
3. sendto():指定服务器地址发送数据
4. recvfrom():接收服务器回发
5. close():关闭 socket
无需连接,直接发送;需提前知道服务器 IP 和端口
UDP 服务器 1. socket():创建 UDP socket
2. bind():绑定固定端口(必须,客户端需定位)
3. recvfrom():接收客户端数据(获取客户端地址)
4. sendto():通过客户端地址回发数据
5. close():关闭 socket
依赖bind()固定端口,否则客户端无法找到服务器

四、TCP 与 UDP 核心差异对比

对比维度 TCP UDP
连接方式 面向连接(需connect 无连接(直接sendto
数据格式 字节流(易粘包,需应用层处理边界) 数据报(无粘包,天然消息边界)
可靠性 可靠(确认、重传、有序) 不可靠(无确认、无重传)
效率 低(连接建立、确认机制耗时) 高(无额外开销,实时性好)
编程重点 处理粘包、连接管理、资源回收 处理地址(sendto/recvfrom)、丢包应对
典型应用 文件传输、聊天、HTTP/HTTPS

网站公告

今日签到

点亮在社区的每一天
去签到