2014-10-06 141 views
0

我使用我的PC作爲服務器。客戶端發送如下消息:「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]; 
}; 

消息發送到服務器的每秒發送所得msgstr看起來是這樣的:

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()); 

但是,我無法找到正確的代碼,將在我的情況下工作。

編輯: 嘗試做這個:

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_.consume(input_buffer_.size()); 

下面是一個完整的最小示例demonstratingconsume()行爲::

#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); 
    } 
    } 
} 
在這種情況下,一旦數據已被從 input_buffer_複製到 msgstr,輸入序列可以與被清除

輸出:

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。時不時地,我有三個組件在字符串中。恩,謝謝! – 2014-10-06 22:57:46

+0

編輯:坦納,再次感謝您的幫助。這是非常豐富和有用的。我想我知道它爲什麼會發生。客戶端每秒發送一條消息,並且服務器在消息發送後應該儘快進行一些操作。但服務器需要時間進行操作,有時需要2秒,有時需要3個時間。所以,緩衝區會隨着客戶端發送的消息而累積。最好的問候, – 2014-10-07 00:45:06

+0

@IgorTupitsyn TCP是一個流,因此沒有定義的消息邊界。因此,代碼必須能夠處理累計值和部分值。例如,發送者可以發送「PART1:part2a」,但對「handle_read()」的調用只能讀取「PAR」。這個[回覆](http://stackoverflow.com/a/22291720/1053968)提供了一些關於如何處理固定大小或可變長度應用程序協議的參考。此外,由於有效負載的大小,禁用Nagle,如[此處](http://stackoverflow.com/a/23871833/1053968)所示,可能會提高性能。 – 2014-10-07 01:33:30

相關問題