使用Boost.Asio发送双文件时接收异常及EOF错误求助
问题描述
通过Boost.Asio向客户端发送img.jpg和message.txt两个文件时,img.jpg可正常接收,但message.txt接收后大小为0。客户端输出如下:
img.jpg: 49152 message.txt: 4096 read: End of file [asio.misc:2]
服务端代码(server.cpp)
#include <iostream> #include <string> #include <fstream> #include <vector> #include <boost/asio.hpp> int main(int argc, char* argv[]) { try { boost::asio::io_context io; std::cout << "Server Start\n"; boost::asio::ip::tcp::acceptor acc(io, boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), 6666)); for (;;) { boost::asio::ip::tcp::socket sock(io); acc.accept(sock); std::vector<std::string> names{ "img.jpg" , "message.txt"}; std::vector<int> sizes{ 49152 , 4096 }; for (int i = 0; i < 2; ++i) { //Send Header boost::asio::streambuf reply; std::ostream header(&reply); header << names[i] << " "; header << std::to_string(sizes[i]) << " "; header << "\r\n"; boost::asio::write(sock, reply); //Send Bytes std::ifstream input(names[i], std::ifstream::binary); std::vector<char> vec(sizes[i]); input.read(&vec[i], sizes[i]); boost::asio::write(sock, boost::asio::buffer(vec, sizes[i])); } sock.close(); } acc.close(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; }
客户端代码(client.cpp)
#include <iostream> #include <string> #include <fstream> #include <vector> #include <boost/asio.hpp> int main(int argc, char* argv[]) { try { boost::asio::io_context io; boost::asio::ip::tcp::resolver resolv(io); boost::asio::ip::tcp::resolver::query q("127.0.0.1", "6666"); boost::asio::ip::tcp::resolver::iterator ep = resolv.resolve(q); boost::asio::ip::tcp::socket sock(io); boost::asio::connect(sock, ep); //Get Files for (int i = 0; i < 2; ++i) { //Read Header boost::asio::streambuf reply; boost::asio::read_until(sock, reply, "\r\n"); std::istream header(&reply); std::string fileName; int fileSize; header >> fileName; header >> fileSize; std::cout << fileName << ": " << fileSize << '\n'; //Read File Data std::ofstream output(fileName, std::ofstream::binary | std::ofstream::app); std::vector<char> vec(fileSize); boost::asio::read(sock, boost::asio::buffer(vec, vec.size())); output.write(&vec[0], vec.size()); output.close(); } sock.close(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 0; }
问题根源与修复方案
1. 服务端文件读取地址错误
这是导致message.txt接收为空的核心问题:
服务端读取文件时使用了input.read(&vec[i], sizes[i]);,第二次循环i=1时,会从vector的第1个元素位置开始写入文件内容,而不是vector的起始地址。这会导致前1个字节是未初始化的垃圾值,且实际文件内容只填充了size-1个字节,同时可能引发越界访问。
修复: 改为读取到vector的起始地址:
input.read(vec.data(), sizes[i]); // 或者兼容旧标准的写法:input.read(&vec[0], sizes[i]);
2. 文件操作未做错误检查
服务端未检查文件是否成功打开、读取是否完整,若message.txt实际大小小于4096或文件不存在,会发送无效数据。建议添加检查:
std::ifstream input(names[i], std::ifstream::binary); if (!input.is_open()) { std::cerr << "无法打开文件: " << names[i] << "\n"; continue; } std::vector<char> vec(sizes[i]); input.read(vec.data(), sizes[i]); // 检查实际读取的字节数 if (input.gcount() != sizes[i]) { std::cerr << "警告:" << names[i] << " 仅读取到 " << input.gcount() << " 字节\n"; } // 发送实际读取的字节数,而非预设大小 boost::asio::write(sock, boost::asio::buffer(vec, input.gcount()));
3. 客户端文件打开模式错误
客户端使用std::ofstream::app模式,会将内容追加到文件末尾,若存在同名旧文件会导致文件异常。应改为覆盖模式(默认截断,只需保留binary):
std::ofstream output(fileName, std::ofstream::binary);
内容的提问来源于stack exchange,提问作者boost
相关产品推荐
相关产品推荐

