You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言使用fread读取传输PDF等二进制文件时数据截断如何解决

问题根因

你不需要替换fread,当前问题完全是报文构造方式错误导致的:

  • sprintf是C标准库中用于处理字符串的格式化函数,%s格式化符的逻辑是遇到\0(NULL字节)就停止写入目标缓冲区,因此data_buf中只要包含NULL字节,后续的二进制内容就不会被拼入message,sprintf返回的count也只会计算到第一个NULL字节的位置,最终sendto只会发送截断后的内容,和fread的逻辑无关。
  • 额外问题:你当前的块编号填充逻辑没有遵循TFTP协议要求的网络字节序(大端序),当块编号超过255时会出现报文错误。

修复方案

1. 替换报文构造逻辑

不要使用字符串处理函数构造二进制协议报文,改用手动填充头部+内存拷贝的方式实现:

size_t nmemb = fread(data_buf, sizeof(char), 512, fp);
...
/* 构造TFTP DATA报文 */
// TFTP DATA报文结构:2字节操作码 + 2字节块编号 + 最多512字节数据
unsigned char message[4 + 512];
// 填充2字节操作码(DATA对应值为3)
message[0] = 0x00;
message[1] = DATA;
// 填充2字节块编号,转换为网络字节序(大端)
message[2] = (block_number >> 8) & 0xFF;
message[3] = block_number & 0xFF;
// 直接拷贝读取到的所有字节,不受NULL字节影响
memcpy(message + 4, data_buf, nmemb);
// 计算实际发送长度:4字节头部 + 实际读取的文件字节数
size_t send_len = 4 + nmemb;
// 发送报文,使用实际长度即可
sendto(sock, message, send_len, 0, (const struct sockaddr *)&server, sizeof(server));

2. 二进制缓冲区调试打印方法

如果你需要调试查看缓冲区的完整内容,不要使用%s格式化打印,改用逐字节打印十六进制的方式:

printf("读取字节数:%d,缓冲区内容:", (int)nmemb);
for (int i = 0; i < nmemb; i++) {
    printf("%02X ", (unsigned char)data_buf[i]);
}
printf("\n");

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 21:45:01