Проблема обмена файлов по TCP boost.asio
Всем добрый вечер, моя задача: сделать клиент и сервер. На клиенте принимается от юзера путь к файлу, а на сервере происходит его принятие. То есть я с клиента отправляю файл на сервер (ну как облачное хранилище я бы сказал). При передаче файла на данный момент со стороны клиента происходит успешно, но на сервер приходит пустой файл и показывает ошибку: read: End of file [asio.misc:2] (или даже иногда ошибку о том, что Невозможно открыть файл для записи: (здесь пусто, а ведь я указал вывести filename в коде)). В чём проблема? Заранее спасибо.
Код сервера:
#include <iostream>
#include <fstream>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
void handle_client(tcp::socket &socket)
{
// Получение размера файла от клиента
std::uint32_t file_size_net;
boost::asio::read(socket, boost::asio::buffer(&file_size_net, sizeof(file_size_net)));
std::uint32_t file_size = ntohl(file_size_net);
// Получение имени файла от клиента
boost::asio::streambuf filename_buffer;
boost::asio::read_until(socket, filename_buffer, '\0');
std::istream filename_stream(&filename_buffer);
std::string filename;
std::getline(filename_stream, filename, '\0');
// Получение файла от клиента
std::ofstream output_file(filename, std::ios::binary);
if (!output_file.is_open())
{
std::cerr << "Невозможно открыть файл для записи: " << filename << std::endl;
return;
}
std::vector<char> buffer(1024);
std::size_t bytes_transferred = 0;
while (bytes_transferred < file_size)
{
std::size_t read_size = std::min(buffer.size(), file_size - bytes_transferred);
std::size_t received = boost::asio::read(socket, boost::asio::buffer(buffer.data(), read_size));
output_file.write(buffer.data(), received);
bytes_transferred += received;
}
output_file.close();
std::cout << "Файл \"" << filename << "\" сохранен на сервере." << std::endl;
}
int main()
{
boost::asio::io_context io_context;
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 12345));
std::cout << "Сервер запущен. Ожидание подключений..." << std::endl;
while (true)
{
tcp::socket socket(io_context);
acceptor.accept(socket);
std::cout << "Клиент подключен: " << socket.remote_endpoint() << std::endl;
try
{
handle_client(socket);
}
catch (std::exception &e)
{
std::cerr << "Ошибка: " << e.what() << std::endl;
}
}
return 0;
}
Код клиента:
#include <iostream>
#include <fstream>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::string get_filename(const std::string &file_path)
{
size_t pos = file_path.find_last_of("/\\");
return (pos == std::string::npos) ? file_path : file_path.substr(pos + 1);
}
void send_file(tcp::socket &socket, const std::string &file_path)
{
try
{
std::string filename = get_filename(file_path);
std::ifstream input_file(file_path, std::ios::binary);
if (!input_file.is_open())
{
std::cerr << "Невозможно открыть файл: " << file_path << std::endl;
return;
}
// Отправка размера файла серверу
input_file.seekg(0, std::ios::end);
int32_t file_size = static_cast<int32_t>(input_file.tellg());
input_file.seekg(0, std::ios::beg);
int32_t file_size_net = htonl(file_size);
boost::asio::write(socket, boost::asio::buffer(reinterpret_cast<const char *>(&file_size_net), sizeof(file_size_net)));
// Отправка имени файла серверу
boost::asio::write(socket, boost::asio::buffer(filename + '\0'));
// Отправка файла серверу
std::vector<char> buffer(1024);
while (!input_file.eof())
{
input_file.read(buffer.data(), buffer.size());
std::size_t bytes_read = static_cast<std::size_t>(input_file.gcount());
if (bytes_read > 0)
{
boost::asio::write(socket, boost::asio::buffer(buffer.data(), bytes_read));
}
}
input_file.close();
if (socket.is_open())
{
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
std::cout << "Файл \"" << file_path << "\" успешно отправлен на сервер." << std::endl;
}
catch (std::exception &e)
{
std::cerr << "Ошибка: " << e.what() << std::endl;
}
}
int main()
{
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
tcp::resolver::results_type endpoints = resolver.resolve("localhost", "12345");
tcp::socket socket(io_context);
boost::asio::connect(socket, endpoints);
if (socket.is_open())
{
std::string file_path;
std::cout << "Введите путь к файлу для отправки на сервер: ";
std::cin >> file_path;
send_file(socket, file_path);
}
else
{
std::cerr << "Ошибка: не удалось подключиться к серверу." << std::endl;
}
return 0;
}