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
相关产品推荐
相关产品推荐

