You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

socket读取内容写入本地文件末尾数据缺失问题排查

问题分析与修复方案

嘿,我一眼就揪出问题所在了——你用错了写入文件的函数!

核心问题

你用fprintf(new_file, "%s", buffer)来写入从socket读取的内容,但%s格式符是专门处理\0结尾的C字符串的,可从socket读取的原始数据(哪怕是HTML文本)完全不保证带有这个终止符:

  • 如果读取的字节里恰好包含\0fprintf会在这个位置直接停止写入,导致后面的内容全部丢失;
  • 如果buffer的有效数据后面没有\0fprintf会越界读取内存,这属于未定义行为,可能写入乱码,或者直接截断内容;
  • 你原代码里的if(bytes_read < MAXSIZE) break;逻辑也有问题,提前中断循环可能漏掉后续的分段数据。

printf("%s", buffer)看起来正常,只是终端输出对\0不敏感,刚好你的显示部分没碰到这个问题而已,属于巧合。

修复后的代码

fprintf换成fwrite,它能精确写入你实际读取到的字节数,完全不依赖字符串终止符。同时调整循环逻辑,去掉不必要的memset

#define MAXSIZE 1000
int bytes_read, thread_fd;
char buffer[MAXSIZE];
FILE* new_file;

if((new_file = fopen(path, "wb+")) == NULL) {
    printf("can not open file \n");
    exit(EXIT_FAILURE);
}

// 每次读取后直接写入精确字节数,无需清空buffer
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0) {
    // fwrite参数:数据源、单个元素大小、元素数量、目标文件
    fwrite(buffer, 1, bytes_read, new_file);
    // 删掉原有的break逻辑——read返回0表示连接关闭,返回-1是错误,小于MAXSIZE是正常的分段传输
}

// 务必关闭文件,确保缓冲区内容全部刷入磁盘
fclose(new_file);

额外说明

  1. 删掉提前break的逻辑:socket传输经常会分多批发送小于MAXSIZE的数据,提前中断会导致后续数据丢失;
  2. 无需memset清空bufferfwrite只会写入你指定的bytes_read字节,buffer后面的残留数据根本不会被处理,清空操作纯粹浪费性能;
  3. 一定要关闭文件:原代码没写fclose,会导致文件缓冲区的剩余内容无法刷新到磁盘,这也是内容缺失的潜在原因。

内容的提问来源于stack exchange,提问作者Darren Col

火山引擎 最新活动