C语言Socket读取HTTP响应时图片文件读取异常问题排查
问题原因
核心问题有2个:
- 内存扩容逻辑计算错误:当前代码判定缓冲区满后,先将
available_buf_size翻倍,再调用realloc时错误的传入了available_buf_size + tot_read作为新缓冲区大小,导致实际分配的缓冲区大小和记录的available_buf_size不匹配,后续读取的写入位置计算会出现偏差。 - 二进制数据长度判断错误:函数仅返回缓冲区指针,没有同步返回实际读取的总字节数
tot_read。文本类HTTP响应没有空字节(\0),你写入文件时用strlen计算长度可以得到正确值;但图片是二进制数据,内容中会存在大量\0,strlen碰到第一个\0就会停止计数,导致实际写入文件的字节数远小于真实读取的字节数,最终图片无法打开。你调试时看到缓冲区内容只有379个字符,也是因为调试器按字符串规则解析,碰到非文本字节就截断显示,实际数据已经完整存在缓冲区中。
修复方案
1. 修正内存扩容逻辑
删除realloc参数中多余的tot_read相加逻辑,保证实际分配的缓冲区大小和available_buf_size记录的数值一致,同时去掉无意义的空缓冲区memset操作。
2. 新增总读取字节数输出
修改函数定义,通过输出参数返回实际读取的总字节数,写入文件时直接用这个值作为写入长度,不要使用任何字符串相关的长度计算函数。
修复后代码示例
// 新增参数tot_out,用于输出实际读取的总字节数 unsigned char *read_unknown_size(int fd, ssize_t *tot_out) { int available_buf_size = 1000, tot_read = 0, curr_read_size; unsigned char *buf = calloc(available_buf_size, 1), *tmp_ptr; if (!buf) { fprintf(stderr,"calloc failed\n"); exit(EXIT_FAILURE); } while ((curr_read_size = (int) read(fd, buf + tot_read, available_buf_size - tot_read)) != 0) { if (curr_read_size == -1) { perror("failed to read\n"); free(buf); exit(EXIT_FAILURE); } tot_read += curr_read_size; if (tot_read >= available_buf_size) { //缓冲区已满,扩容 available_buf_size *= 2; // 修正realloc大小计算 tmp_ptr = realloc(buf, available_buf_size); if (!tmp_ptr) { fprintf(stderr,"realloc failed\n"); free(buf); exit(EXIT_FAILURE); } buf = tmp_ptr; } } *tot_out = tot_read; return buf; }
调用示例
ssize_t read_len; unsigned char *resp = read_unknown_size(fd, &read_len); // 写入文件时用read_len作为长度参数,不要用strlen(resp) fwrite(resp, 1, read_len, fp);
额外注意事项
当前实现依赖服务端返回Connection: close头才会终止读取,如果后续需要适配长连接场景,建议先解析HTTP响应头的Content-Length字段,按指定长度读取响应体,避免出现读取超时或多读的问题。
内容的提问来源于stack exchange,提问作者RedYoel
相关产品推荐
相关产品推荐

