Проблема не в сокете, а в том, как вы пишете файл на сервере.
std::ofstream file("transferd.bin");
cout << data; // you cannot print binary data like this on the standard output!
file << data;
file.close();
Приведенный выше фрагмент неверен, поскольку оператор <<
используется для ASCII, а не для двоичных данных!
Простым решением было бы заменить его следующим фрагментом:
std::ofstream file("transferd.bin");
file.write(data, buf.size());
Вторая часть вопроса, конечно, более сложная и требует большого изменения кода.
Суть в том, что вы не можете передать весь контент одновременно, но вы должны разделить передачу на маленькие кусочки.
Одним из решений может быть отправка небольшого заголовка с некоторой информацией, например, общим количеством байтов передачи. таким образом, сервер может читать чанк по чанку до тех пор, пока не будет завершена вся передача.
Сообщение содержит файл заголовка, содержащий общий размер сообщения, количество чанков. У каждого чанка есть небольшой заголовок, указывающий размер чанка или, например, индекс чанка, если вы хотите переключиться на UDP.
После фрагмента сервера
#include <array>
#include <boost/asio.hpp>
#include <cstddef>
#include <fstream>
#include <iostream>
#include <vector>
using namespace boost::asio;
using ip::tcp;
using std::cout;
using std::endl;
using std::string;
struct MessageHeader {
int64_t totalSize;
int64_t chunkCount;
};
struct ChunkHeader {
int64_t index;
int64_t size;
};
MessageHeader parseHeader(const char* data) {
MessageHeader header;
memcpy(&header, data, sizeof(MessageHeader));
return header;
}
ChunkHeader parseChunkHeader(const char* data) {
ChunkHeader header;
memcpy(&header, data, sizeof(MessageHeader));
return header;
}
MessageHeader readHeader(tcp::socket& socket) {
std::array<char, sizeof(MessageHeader)> buffer;
boost::asio::read(socket, boost::asio::buffer(buffer));
return parseHeader(buffer.data());
}
ChunkHeader readChunkHeader(tcp::socket& socket) {
std::array<char, sizeof(ChunkHeader)> buffer;
boost::asio::read(socket, boost::asio::buffer(buffer));
return parseChunkHeader(buffer.data());
}
std::vector<char> readChunkMessage(tcp::socket& socket) {
auto chunkHeader = readChunkHeader(socket);
std::vector<char> chunk(chunkHeader.size);
boost::asio::read(socket, boost::asio::buffer(chunk));
return chunk;
}
int main() {
boost::asio::io_service io_service;
// listen
tcp::acceptor acceptor_(io_service, tcp::endpoint(tcp::v4(), 3333));
// socket
tcp::socket socket_(io_service);
// waiting
acceptor_.accept(socket_);
auto messageHeader = readHeader(socket_);
for (auto chunkIndex = 0ll; chunkIndex != messageHeader.chunkCount; ++chunkIndex) {
auto chunk = readChunkMessage(socket_);
// open the file in append mode
std::ofstream file("transferd.bin", std::ofstream::app);
file.write(chunk.data(), chunk.size());
}
// response
boost::asio::write(socket_, boost::asio::buffer("data recived"));
return 0;
}
Приведенное выше решение имеет недостатки, поскольку все является синхронным, и если клиент завершит работу в середине передачи, сервер застрянет: D
Лучшее решение - превратить это в асин c код ... но это слишком много всего для начинающий!