从FTP服务器下载文件后损坏,请求分析相关代码问题
FTP下载文件损坏问题排查
嘿,我看了你的代码,马上发现几个会导致文件损坏的关键点,咱们一个个拆解:
buffer数据被覆盖,丢失大部分接收内容
你现在每次调用recv(dataSocket, buffer, 30000, 0)时,新接收的数据会直接覆盖buffer里之前的内容。最后执行fout.write(buffer, size)的时候,你只把最后一次recv得到的那部分数据写入了文件,前面接收的所有字节都丢失了!这是文件损坏最直接的原因。
解决办法是用一个动态容器来累积所有接收的数据,比如C++的vector<char>:vector<char> receivedData; char buffer[30000]; int iResult; int size = 0; do { iResult = recv(dataSocket, buffer, sizeof(buffer), 0); if (iResult > 0) { printf("Bytes received: %d\n", iResult); size += iResult; // 将本次接收的数据追加到容器末尾 receivedData.insert(receivedData.end(), buffer, buffer + iResult); } else if (iResult == 0) { printf("Connection closed\n"); } else { printf("recv failed: %d\n", WSAGetLastError()); break; // 出错后终止循环,避免无效处理 } } while (iResult > 0); cout << "the full size: " << size << endl; ofstream fout("test.png", ios_base::binary); fout.write(receivedData.data(), receivedData.size()); fout.close(); // 确保数据全部写入磁盘未切换到FTP二进制传输模式
FTP默认使用文本模式(TYPE A),如果传输png这类二进制文件,服务器会自动转换换行符(比如把\n转为\r\n),这会彻底破坏二进制文件的结构。你需要在发送RETR命令前,先发送TYPE I\r\n命令切换到二进制模式:// 先切换到二进制传输模式 send(serverSocket, "TYPE I\r\n", strlen("TYPE I\r\n"), 0); // 再发送下载命令 send(serverSocket, "RETR user.png\r\n", strlen("RETR user.png\r\n"), 0);额外的优化建议
- 调用
send时,用strlen()计算命令的字节数,代替硬写的15,避免命令长度变化导致发送不完整。 - 写完文件后显式调用
fout.close(),确保所有缓存的数据都刷新到磁盘,避免数据丢失。
- 调用
内容的提问来源于stack exchange,提问作者user8535817




