EOF с boost :: asio :: read - PullRequest
       32

EOF с boost :: asio :: read

3 голосов
/ 09 октября 2011

У меня небольшая проблема с моим клиент-серверным приложением на C ++. Он использует boost :: asio для удаленной связи и протокольные буферы для сериализации. Здесь клиент:

// Time to write
char sizeMessage[20];
string content = request.SerializeAsString();
size_t request_length = content.size();            

boost::asio::write(s, boost::asio::buffer(content.c_str(), request_length));
boost::system::error_code error;

boost::asio::read(s, boost::asio::buffer(sizeMessage, 20));

int bufferSize = atoi(sizeMessage);
char* responseString = new char[bufferSize];        
size_t reply_length = boost::asio::read(s, boost::asio::buffer(responseString, bufferSize), boost::asio::transfer_all(), error);
if(!error){
    response.ParseFromArray((const void*)responseString, reply_length);
    success = true;                
}else{
    response.set_status(ExecResponse::ERROR);                
}


delete[] responseString;

В этом конкретном сценарии моего приложения ответ сервера может варьироваться по размеру, от нескольких байтов до нескольких МБ. По этой причине сервер сначала записывает размер вывода, который я затем использую, чтобы выделить нужный объем памяти для моего буфера. Я почему-то получаю ошибку при чтении данных (размер всегда правильно читается). Небольшая отладка показала asio.misc: 2, который, по поиску, выяснив, что это EOF (фактически, число прочитанных байтов меньше размера буфера). Вот серверная сторона:

ExecResponse response;
ExecutionServerHandler execHandler(this->sharedData);
execHandler.process(rd, request, response);   
string output = response.SerializeAsString();
//First write the length
ostringstream stringLength;
stringLength << output.size();
response.PrintDebugString();
string lengthString = stringLength.str();    
size_t bw = ba::write(bsocket_, ba::buffer(lengthString));
bw = ba::write(bsocket_, ba::buffer(output));

На самом деле я впервые работаю с boost, поэтому я не опытный разработчик. Кроме того, важно отметить, что в других частях моего приложения этот механизм работает, но мои другие сообщения имеют некоторые различия: хотя они все еще имеют переменный размер, они всегда малы (несколько сотен байт). Сторона сервера идентична, но на стороне клиента я использую boost :: asio :: Transfer_at_least (1), и я не пишу размер заранее. Если я применил эти изменения к этому случаю, я заметил, что вызов read может извлечь до 65536 байт и не более (возвращая EOF преждевременно). Мои машины для разработки - это Debian 5 и Ubuntu 10.04 для 64 бит, и я получаю такое же поведение для Boost 1.40 и 1.47. Если кто-то понимает, что я делаю что-то не так, я был бы признателен. Я отчаянно пытаюсь заставить это работать.

Ответы [ 2 ]

4 голосов
/ 09 октября 2011

Похоже, в вашем протоколе может быть проблема: Как ваш клиент узнает длину lengthString? Вы преобразовываете произвольное число в строку, а затем записываете это в буфер, без заполнения или что-то еще? Не видя больше кода, его трудно увидеть, но это определенно выглядит подозрительно.

Обычно, имея сообщения переменной длины, вы определяете какой-то формат пакета, например, поле длины составляет 4 байта (выберите правильное количество байтов для ваших сообщений), за которым следует сообщение, а затем вы можете отправить (в данном случае) int клиенту, который сначала прочитает 4 байта, а затем узнает, сколько еще байтов читать из сокета. Возможно, вы захотите взглянуть на такие функции, как htons и т. Д.

Если у вас есть заголовок переменной длины, у вас будет какой-то разделитель для чтения. Этот тип заголовка показан в примерах HTTP asio, где "\ r \ n \ r \ n" - используемый разделитель. Этот пример также может быть полезен для вас, поскольку, как сказал Рейма, вам потребуется изменить клиента, чтобы сначала прочитать заголовок, а затем текст сообщения.

1 голос
/ 27 января 2015

Кажется, что вы отправляете запрос на сервер, чтобы спросить размер предстоящего ответа, но поскольку потоки TCP не имеют разделителя сами по себе, вы можете получить размер вместе с частью или всем ответом, ожидаятолько размер!Вам следует принять во внимание эту часть данных, прежде чем пытаться прочитать оставшуюся часть ответа (и, очевидно, дождаться меньшего количества байтов).

...