2014-10-06 6 views
0

Я использую свой ПК в качестве сервера. Клиент отправляет такие сообщения, как: «PART1: Part2», и сервер выполняет необходимые действия. Я использую boost asio для кода сервера.boost asio async_read: прочитанное сообщение добавляет к себе

void start_read() 
    { 
     boost::asio::async_read(socket_, input_buffer_, 
      boost::asio::transfer_at_least(1), 
      boost::bind(&tcp_connection::handle_read, shared_from_this(), 
      boost::asio::placeholders::error)); 
    } 

    // When stream is received handle the message from the client 
    void handle_read(const boost::system::error_code& error) 
    { 
     if (!error) 
     { 
      boost::asio::streambuf::const_buffers_type bufs = input_buffer_.data(); 
      std::string msgstr(boost::asio::buffers_begin(bufs), 
           boost::asio::buffers_begin(bufs) + 
           input_buffer_.size()); 

      std::vector<std::string> msgVector; 
      boost::split(msgVector, msgstr, boost::is_any_of(":")); 

      messageFromClient_ = msgVector[0]; 
      valueFromClient_ = msgVector[1]; 
}; 

сообщения на сервер отправляются каждый второй и в результате выводе, выглядит следующим образом:

PART1:part2a 
PART1:part2bPART1:part2b 
PART1:part2cPART1:part2cPART1:part2c 
PART1:part2dPART1:part2dPART1:part2dPART1:part2d 

Это не то, что я хочу. Я не хочу, чтобы включить данные из предыдущего буфера, то есть я хочу это:

PART1:part2a 
PART1:part2b 
PART1:part2c 
PART1:part2d 

Я понимаю, что проблема, скорее всего, лежит здесь:

  std::string msgstr(boost::asio::buffers_begin(bufs), 
           boost::asio::buffers_begin(bufs) + 
           input_buffer_.size()); 

Однако, я не могу найти правильный код, будет работать в моем случае.

EDIT: Пытался сделать это вместо:

std::istream response_istream(&input_buffer_); 
std::string msgstr; 
response_istream >> msgstr; 

Первые три раза, я получаю то, что мне нужно, но тогда сообщение умножается. Это всегда так:

PART1:part2a 
PART1:part2b 
PART1:part2c 
PART1:part2dPART1:part2d 
PART1:part2ePART1:part2e 
PART1:part2fPART1:part2fPART1:part2fPART1:part2f 
PART1:part2gPART1:part2g 

Большое спасибо заранее.

ответ

3

Функция-член streambuf::data() возвращает буферы, представляющие входную последовательность. Чтобы избежать повторного доступа к данным, можно использовать функцию-член streambuf::consume() для удаления символов с начала входной последовательности. В этом случае после того, как данные были скопированы из input_buffer_ в msgstr, входная последовательность может быть очищен с:

input_buffer_.consume(input_buffer_.size()); 

Вот полный минимальный пример demonstrating поведение consume():

#include <iostream> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/lexical_cast.hpp> 

// This example is not interested in the handlers, so provide a noop function 
// that will be passed to bind to meet the handler concept requirements. 
void noop() {} 

int main() 
{ 
    using boost::asio::ip::tcp; 
    boost::asio::io_service io_service; 

    // Create all I/O objects. 
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0)); 
    tcp::socket server_socket(io_service); 
    tcp::socket client_socket(io_service); 

    // Connect client and server sockets. 
    acceptor.async_accept(server_socket, boost::bind(&noop)); 
    client_socket.async_connect(acceptor.local_endpoint(), boost::bind(&noop)); 
    io_service.run(); 

    // No-consuming case. 
    { 
    std::cout << "Non-consuming example" << std::endl; 
    boost::asio::streambuf streambuf; 
    for (int i = 0; i < 5; ++i) 
    { 
     std::string data = "test"; 
     data += boost::lexical_cast<std::string>(i); 

     // Write to server. 
     std::size_t bytes_transferred = 
      write(client_socket, boost::asio::buffer(data)); 

     // Read from client. 
     read(server_socket, streambuf, 
      boost::asio::transfer_exactly(bytes_transferred)); 

     // Print results. 
     std::string read_data(
     boost::asio::buffers_begin(streambuf.data()), 
     boost::asio::buffers_end(streambuf.data())); 
     std::cout << "size: " << streambuf.size() << ", " 
       << "read: " << read_data << std::endl; 
    } 
    } 

    // Consuming case. 
    { 
    std::cout << "Consuming example" << std::endl; 
    boost::asio::streambuf streambuf; 
    for (int i = 0; i < 5; ++i) 
    { 
     std::string data = "test"; 
     data += boost::lexical_cast<std::string>(i); 

     // Write to server. 
     std::size_t bytes_transferred = 
      write(client_socket, boost::asio::buffer(data)); 

     // Read from client. 
     read(server_socket, streambuf, 
      boost::asio::transfer_exactly(bytes_transferred)); 

     // Print results. 
     std::string read_data(
     boost::asio::buffers_begin(streambuf.data()), 
     boost::asio::buffers_end(streambuf.data())); 
     std::cout << "size: " << streambuf.size() << ", " 
       << "read: " << read_data << std::endl; 

     streambuf.consume(bytes_transferred); 
    } 
    } 
} 

И выход:

Non-consuming example 
size: 5, read: test0 
size: 10, read: test0test1 
size: 15, read: test0test1test2 
size: 20, read: test0test1test2test3 
size: 25, read: test0test1test2test3test4 
Consuming example 
size: 5, read: test0 
size: 5, read: test1 
size: 5, read: test2 
size: 5, read: test3 
size: 5, read: test4 

Обратите внимание, что в случае потребления предыдущие данные отбрасываются.

+0

Большое спасибо, Таннер. У меня есть это сейчас: 'boost :: asio :: streambuf :: const_buffers_type bufs = input_buffer_.data();' 'std :: string msgstr (boost :: asio :: buffers_begin (bufs), boost :: asio :: buffers_begin (bufs) + input_buffer_.size()); '' input_buffer_.consume (input_buffer_.size()); это делает его проблемой, как я показал в своем тексте после редактирования, т. е. первые три раза, строка является нормальной, но тогда он выглядит так: PART1: part2aPart1: part2a. Время от времени у меня есть три компонента в строке. Хм .. Спасибо! –

+0

EDIT: Таннер, снова большое спасибо за вашу помощь. Это очень информативно и полезно. Кажется, я знаю, почему это происходит. Клиент отправляет сообщение каждую секунду, и сервер должен совершать некоторые манипуляции, как только будет отправлено сообщение. Но серверу требуется время для выполнения манипуляций, иногда 2 секунды, иногда 3. Таким образом, буфер накапливается с сообщениями, отправленными от клиента. С уважением, –

+0

@IgorTupitsyn TCP - это поток и, следовательно, не имеет определенной границы сообщения. Следовательно, код должен иметь возможность обрабатывать накопленные значения и частичные значения. Например, отправитель может отправить «PART1: part2a», но вызов 'handle_read()' только читает «PAR».В этом [ответе] (http://stackoverflow.com/a/22291720/1053968) приводятся некоторые рекомендации о том, как обрабатывать это для протоколов приложений фиксированного размера или переменной длины. Кроме того, из-за размера полезной нагрузки отключение Nagle, как показано [здесь] (http://stackoverflow.com/a/23871833/1053968), может повысить производительность. –

 Смежные вопросы

  • Нет связанных вопросов^_^