网络编程:问题与机制
核心要点速览
- 字节序:主机序(小端 / 大端)→ 网络序(大端),转换函数
htons()/ntohs()、htonl()/ntohl() - TCP 核心问题:粘包 / 半包(流式无边界),解决方案:固定长度、分隔符、消息头 + 消息体(最常用)
- UDP 特性:无粘包、可能丢包、数据报大小受限,读写用
sendto()/recvfrom() - 并发模型:多线程 / 多进程(简单低并发)、I/O 多路复用(epoll 核心,高并发)、线程池 / 进程池(平衡开销)
- 可靠性保障:超时(
SO_RCVTIMEO)、心跳(应用层 / TCP keepalive)、重连(指数退避) - 序列化:Protobuf/FlatBuffers(高性能)、JSON/XML(可读性)、自定义二进制(紧凑)
- 安全防护:SYN 洪水(SYN Cookie)、数据加密(SSL/TLS)、限流(防火墙 / 应用层)
一、字节序转换(跨平台通信基础)
- 主机字节序:CPU 存储数据的方式,分小端(低字节存低地址,主流架构)和大端(低字节存高地址)。
- 网络字节序:统一为大端(避免跨平台差异),所有网络传输数据需转换为此格式。
- 核心转换函数:
- 短整型(2 字节):
htons()(主机→网络)、ntohs()(网络→主机) - 长整型(4 字节):
htonl()(主机→网络)、ntohl()(网络→主机)
- 短整型(2 字节):
二、TCP 粘包与半包问题
TCP 是字节流协议(无消息边界),导致接收方无法直接区分完整消息。
1. 问题成因
- 粘包:Nagle 算法合并小数据包、接收方缓冲区未及时读取,多个消息合并为一个 TCP 报文。
- 半包:消息超过 MSS(最大报文段长度)被拆分、接收方缓冲区不足,一个消息仅读取部分数据。
2. 解决方案(应用层定义消息边界)
| 方案类型 | 核心逻辑 | 优点 | 缺点 |
|---|---|---|---|
| 固定长度消息 | 约定每个消息长度固定,接收方按固定长度读取 | 实现简单 | 灵活性差,消息长度不确定时浪费带宽 |
| 分隔符标记 | 用特殊字符(如\r\n)作为消息结束标记 |
灵活,无需预设长度 | 需处理消息内容包含分隔符的情况 |
| 消息头 + 消息体 | 4 字节消息头存储消息体长度,先读头再读体 | 通用、灵活,无冗余 | 需额外解析消息头,逻辑稍复杂 |
- 最常用:消息头 + 消息体(兼顾灵活性和效率)。
三、UDP 数据报(无连接传输)
1. 核心特性
- 无连接、无粘包(数据报独立传输)、不可靠(可能丢包、乱序)。
- 数据报大小受限(通常不超过 MTU,约 1500 字节),超出会被分片或丢弃。
2. 关键读写函数
sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen):指定目标地址发送数据。recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen):接收数据并获取源地址。
四、并发连接处理(服务器高并发核心)
1. 常见并发模型对比
| 模型类型 | 核心原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 多线程 / 多进程(每连接一个) | 为每个连接创建独立线程 / 进程处理 | 实现简单,无共享状态问题 | 资源开销大,支持并发数有限(几千) | 连接数少、逻辑复杂(如数据库连接) |
| I/O 多路复用(select/poll/epoll) | 单线程管理多个连接,仅处理有事件的连接 | 资源开销低,支持高并发(百万级) | 逻辑复杂,需处理非阻塞 I/O | Web 服务器、即时通讯等高并发场景 |
| 线程池 / 进程池 | 预先创建固定线程 / 进程,分配连接处理 | 平衡资源开销与并发能力 | 线程数固定,极端情况可能瓶颈 | 中等并发、连接生命周期短的场景 |
2. epoll 核心优势(Linux 高并发首选)
- 事件驱动而非轮询:仅通知就绪连接,效率 O (1)(select/poll 为 O (n))。
- 共享内存:fd 集合存储在内核,避免用户态与内核态频繁拷贝。
- 支持两种触发模式:
- 水平触发(LT,默认):缓冲区有数据则持续通知,易用不易漏。
- 边缘触发(ET):仅数据到来时通知一次,需一次性读完缓冲区,效率更高。
五、连接可靠性保障(避免 “假死” 连接)
1. 超时处理
- 问题:
recv()/send()默认阻塞,连接异常时可能永久阻塞。 - 解决方案:用
setsockopt()设置超时参数(SO_RCVTIMEO接收超时、SO_SNDTIMEO发送超时),或结合epoll_wait()的超时参数。
2. 心跳机制(检测连接存活)
- 原理:定期发送心跳包,未收到回应则判定连接失效。
- 实现方式:
- 应用层心跳:业务协议中加入固定格式心跳包(如每 30 秒发送,5 秒未回应断连)。
- TCP keepalive:内核层定期发送探测包,默认超时较长(需调整参数)。
3. 断连重连(客户端)
- 核心策略:指数退避(重连间隔 1s→2s→4s→…→上限 60s),避免频繁重试冲击服务器。
- 限制:超过最大重试次数后报警(如网络彻底故障)。
六、数据序列化与反序列化(跨平台传输)
核心要求:跨平台兼容、效率、可读性
| 方案类型 | 核心特点 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 自定义二进制格式 | 手动打包 / 解析,处理大小端 | 紧凑高效,字节流小 | 开发复杂,兼容性差 | 对效率要求极高、协议固定的场景 |
| JSON/XML(文本格式) | 文本标记数据结构 | 可读性好,跨平台性强 | 冗余大,解析效率低 | 调试友好、数据量小的场景 |
| Protobuf/FlatBuffers | IDL 定义结构,自动生成代码(二进制) | 效率高,支持版本兼容 | 可读性差,需工具解析 | 高性能场景(游戏、分布式系统) |
七、网络安全与攻击防护(面试高频)
1. SYN 洪水攻击
- 原理:攻击者发送大量
SYN报文但不完成三次握手,耗尽服务器半连接队列资源。 - 防护:开启 SYN Cookie(服务器用 Cookie 验证请求合法性,不维护半连接队列)。
2. 数据传输加密
- 方案:用 SSL/TLS 协议(如 HTTPS)对传输数据加密,避免明文被窃听或篡改。
3. 端口扫描与限流
- 防护:防火墙限制异常 IP 连接频率,或应用层实现限流(如单 IP 每秒最多 10 次连接)。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 肖恩的博客!
评论

