4. 固定长度法
聊完了定界符法,咱们来看看另一种思路——固定长度法。
这个方法,说白了就是「一刀切」。发送方和接收方事先约定好,每个数据包都固定为 N 个字节。发送的时候,如果数据不够 N 字节,就用特殊字符(比如 '\0')补齐;如果数据超过了 N 字节,那就拆成多个包发送。
接收方这边就简单了——每次从缓冲区里读 N 个字节,就是一个完整的包。不需要找分隔符,也不需要解析长度字段,直接按字节数切分就行。
4.1 原理讲解
固定长度法的核心思想,就是「以长度定边界」。双方约定一个固定长度 L,每个消息体都必须是 L 字节。
- 发送方:将消息序列化为字节数组。如果长度小于 L,在末尾补零(或补空格)到 L 字节。如果长度大于 L,则截断或分片发送。
- 接收方:维护一个接收缓冲区。每次从缓冲区读取 L 字节,作为一个完整的消息处理。如果缓冲区不足 L 字节,则等待更多数据。
嗯,这里要注意:补全字符的选择很关键。我见过有人用 '\0' 补,也有人用空格补。如果你传输的是文本协议,用空格补看起来更友好;如果是二进制协议,用 '\0' 更常见。
为什么会有人用这种方法?说白了,就是「简单粗暴」。你想想看,接收方不需要做任何解析,不需要查找分隔符,不需要计算长度。直接 memcpy 或者 read 固定字节数,性能极高。
4.2 代码实现
我直接给你一个完整的 C 语言示例。这个例子演示了如何用固定长度法发送和接收消息。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define FIXED_LENGTH 64 // 固定长度 64 字节
#define BUFFER_SIZE 1024
// 发送固定长度的消息
int send_fixed(int sockfd, const char *msg, int msg_len) {
char buffer[FIXED_LENGTH];
memset(buffer, 0, FIXED_LENGTH); // 用 '\0' 补齐
if (msg_len > FIXED_LENGTH) {
// 消息太长,截断或分片
// 我这里选择截断,实际项目中可以分片发送
memcpy(buffer, msg, FIXED_LENGTH);
} else {
memcpy(buffer, msg, msg_len);
}
return send(sockfd, buffer, FIXED_LENGTH, 0);
}
// 接收固定长度的消息
int recv_fixed(int sockfd, char *out_buf, int buf_size) {
char buffer[FIXED_LENGTH];
int total = 0;
while (total < FIXED_LENGTH) {
int n = recv(sockfd, buffer + total, FIXED_LENGTH - total, 0);
if (n <= 0) {
return n; // 连接关闭或出错
}
total += n;
}
// 去掉补齐的 '\0',拷贝到输出缓冲区
int real_len = strnlen(buffer, FIXED_LENGTH);
if (real_len > buf_size - 1) {
real_len = buf_size - 1;
}
memcpy(out_buf, buffer, real_len);
out_buf[real_len] = '\0';
return real_len;
}
// 使用示例
int main() {
// 假设已经建立连接 sockfd
int sockfd = 0; // 实际项目中需要创建 socket
// 发送 "Hello" 这个短消息
char *msg = "Hello";
send_fixed(sockfd, msg, strlen(msg));
// 接收端
char recv_buf[256];
int len = recv_fixed(sockfd, recv_buf, sizeof(recv_buf));
if (len > 0) {
printf("Received: %s (len=%d)\n", recv_buf, len);
}
return 0;
}
4.3 优缺点分析
| 优点 | 缺点 |
|---|---|
| 实现简单,代码量少 | 浪费带宽:短消息也要补齐到固定长度 |
| 接收方无需解析,性能高 | 灵活性差:消息长度固定,无法动态调整 |
| 不会出现粘包拆包问题 | 长消息需要截断或分片,增加复杂度 |
| 内存管理简单,可预分配缓冲区 | 补齐字符可能被误认为是有效数据 |
| 适合硬件实现,处理速度快 | 协议升级困难,长度变更需要双方同步 |
说白了,固定长度法就是「用空间换时间」。你牺牲了带宽利用率,换来了极致的简单和性能。
4.4 适用场景
固定长度法不是万能的,但在某些场景下,它是最优解。
- 嵌入式系统:资源受限,需要简单可靠的通信协议。比如传感器数据采集,每个数据包都是固定格式。
- 音视频传输:音视频帧通常有固定大小(如 1024 字节一帧),用固定长度法天然匹配。
- 硬件接口通信:比如 SPI、I2C 等硬件协议,通常以固定长度传输数据块。
- 日志采集:每条日志记录长度固定,方便批量写入和读取。
- 金融交易:某些高频交易场景,消息格式固定,追求极致的处理速度。
你想想看,如果你的消息长度本身就差不多(比如 GPS 坐标数据,每条都是 20 字节左右),那固定长度法就是最合适的选择。没必要为了「节省那点带宽」而引入复杂的协议解析。
4.5 核心逻辑流程图
下面我用一张 SVG 图,把固定长度法的核心流程画出来。你可以看到,发送和接收的逻辑都非常清晰。
从这张图可以看出来,固定长度法的流程非常线性。发送方就是「补全→发送」,接收方就是「接收→切分」。没有循环解析,没有状态机,简单到不能再简单。
好了,固定长度法就讲到这里。它的优缺点都很鲜明,适用场景也很明确。你只要记住:简单、高效、浪费带宽,这三个关键词就够了。
可可精品资料库