在C/C++中通过TCP传输.mp4等二进制文件出现损坏该如何解决?
问题根因与修复方案
你的文件损坏问题和二进制文件的特殊处理无关,完全是服务端代码的逻辑错误导致的,具体问题和修复方法如下:
核心错误点
- 服务端接收到数据后执行了
buf[m_result] = '\0':这个操作会直接修改原始二进制数据的最后一个字节为0,同时如果你的buf大小刚好为BUFFER_SIZE,当recv返回等于BUFFER_SIZE时,这个写入操作会发生数组越界。对于文本文件来说终止符的影响不明显,但二进制文件会直接被破坏。 - 使用流插入运算符
<<写入二进制数据:<<运算符针对char*类型的参数,会默认读到\0就停止写入,而MP4、ZIP这类二进制文件内部本身就存在大量\0字符,会导致实际写入文件的字节数远小于你实际收到的m_result字节数。 std::ofstream对象定义在循环内部:每次循环都会创建新的文件流对象,is_open()判断永远返回false,每次循环都会重新执行open操作,虽然用了追加模式不会丢数据,但属于不必要的性能损耗,也增加了出错概率。
修复后的服务端核心代码
// 接收文件前先打开文件,移到循环外部 std::ofstream outfile(m_filename.c_str(), std::ios_base::binary | std::ios_base::trunc); if (!outfile.is_open()) { // 处理文件打开失败逻辑 exit_sys("open file"); } //some stuff... for (;;) { if ((m_result = recv(epes[i].data.fd, buf, BUFFER_SIZE, 0)) == -1) { if (errno == EAGAIN) break; exit_sys("recv"); } if (m_result > 0) { // 删掉buf[m_result] = '\0' 这行 // 改用write方法指定写入长度 outfile.write(buf, m_result); m_filesize -= m_result; std::cout << "count : " << m_result << '\n'; std::cout << "remain data : " << m_filesize << '\n'; if(!m_filesize){ outfile.close(); m_fileTransferReady = 0; std::cout<<"File transfer stop\n"; if (send(epes[i].data.fd, "transferok", 10, 0) == -1) exit_sys("send"); break; } } //some stuff for else }
额外优化建议
- 客户端需要处理
sendfile的异常返回:如果返回值为-1时errno为EINTR、EAGAIN/EWOULDBLOCK,需要重试发送,不要直接终止循环,避免网络波动导致传输中断。 - 传输结束后服务端可以校验最终写入的文件大小和提前收到的文件总大小是否一致,避免极端场景下的数据丢失。
- 可以添加写入失败的校验,判断
outfile.good()的状态,捕获磁盘满、权限不足等写入错误。
内容的提问来源于stack exchange,提问作者Purgoufr
相关产品推荐
相关产品推荐

