C语言实现HTTP服务器处理视频POST请求:无法检测末尾boundary
问题分析与解决方法
核心问题
strstr()不支持二进制数据:strstr()是字符串查找函数,会把遇到的第一个'\0'当作字符串结束符停止搜索。但视频是二进制文件,内容中大概率包含'\0',直接用它搜索会提前终止,找不到后续的boundary。- Boundary可能跨缓冲区:你每次固定读取
BUFFERSIZE字节,但boundary可能刚好被拆分在两个连续的缓冲区中,单次搜索单个缓冲区自然找不到完整的boundary。 - 写入逻辑冗余:当
read()返回的实际字节数re小于BUFFERSIZE时,你依然写入BUFFERSIZE字节,会把缓冲区中未被覆盖的0写入文件,虽然不影响boundary存在,但属于无效写入。
修复步骤
1. 替换strstr()为二进制安全的查找函数
自己实现一个基于内存块的查找函数,不依赖'\0'作为结束标志,根据实际读取的字节长度搜索:
// 二进制安全的内存查找,返回首次匹配的指针,未找到返回NULL void* mem_find(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len) { if (needle_len == 0 || haystack_len < needle_len) { return NULL; } const unsigned char* h = (const unsigned char*)haystack; const unsigned char* n = (const unsigned char*)needle; for (size_t i = 0; i <= haystack_len - needle_len; ++i) { size_t j; for (j = 0; j < needle_len; ++j) { if (h[i + j] != n[j]) { break; } } if (j == needle_len) { return (void*)(h + i); } } return NULL; }
2. 处理跨缓冲区的Boundary
保留上一次缓冲区中未搜索完的尾部数据(长度为boundary长度-1),避免跨缓冲区的boundary被拆分后无法匹配:
#define BOUNDARY_LEN (strlen(boundaryarr)) unsigned char buf[BUFFERSIZE + BOUNDARY_LEN - 1]; // 预留空间存上一次的尾部 size_t leftover = 0; // 上一次未处理的尾部字节数 int fla = 0; void* endoffile = NULL; while (!endoffile) { memset(buf + leftover, 0, BUFFERSIZE); int re = read(i, buf + leftover, BUFFERSIZE); if (re <= 0) { if (fla == 0) { fla = 1; continue; } else { break; } } if (fla == 1) { fla = 0; } size_t total_len = leftover + re; num_read += re; // 用自定义函数查找boundary endoffile = mem_find(buf, total_len, boundaryarr, BOUNDARY_LEN); if (endoffile) { // 计算写入长度:从buf开头到boundary前的位置 size_t write_len = (unsigned char*)endoffile - buf - 3; // 对应原逻辑的-3 if (write_len > 0) { write(newfd, buf, write_len); } close(newfd); } else { // 保留最后BOUNDARY_LEN-1字节,用于下一次搜索跨缓冲区的boundary if (total_len >= BOUNDARY_LEN - 1) { memcpy(buf, buf + total_len - (BOUNDARY_LEN - 1), BOUNDARY_LEN - 1); leftover = BOUNDARY_LEN - 1; // 写入除保留部分外的有效数据 write(newfd, buf, total_len - leftover); } else { // 当前总长度不足boundary长度,全部保留 leftover = total_len; } } }
3. 修正写入长度问题
修复后的代码只写入实际读取到的有效数据,避免了原逻辑中写入多余0的问题。
额外说明
- 打印缓冲区看不到boundary是因为视频二进制数据中的不可打印字符干扰了终端输出,实际数据是存在的,所以写入文件后能正常显示。
- 确认
boundaryarr格式正确:HTTP multipart的boundary在内容中是以--{boundary}开头的,如果你提取的boundary没有包含前面的--,需要补上,否则会匹配失败。
内容的提问来源于stack exchange,提问作者Eric_huang1026
相关产品推荐
相关产品推荐

