2010-01-02 49 views
0

我無法implmenting的功能這裏記錄的第三個參數: http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/async_read_until/overload4.html 我想什麼,能夠做的就是利用回調在async_read_until的第三個參數檢測,當一個完整的塊已經到達。我的數據包有以下格式。幫助,async_read_until

  • 1字節ID(該數據的語義含義)
  • 無符號整數(在數據字節的數量,因爲一些數據塊可以改變大小)
  • 有效載荷

綜觀在文檔中的示例代碼,我有點困惑我應該如何能夠提取一個字節,更不用說來自開始和結束迭代器的unsigned int。 我實例化我的迭代器作爲 typedef boost::asio::buffers_iterator< boost::asio::streambuf::const_buffers_type> iterator;

但即使如此,我不知道那是什麼類型的,因爲我不知道什麼是const_buffers_type。我跟隨了文檔中的一些鏈接,發現它是「實現定義的」,但我想我可能是錯的。 所以我的兩個具體問題是:

  1. 我怎樣才能使用這兩個迭代器來讀取一個unsigned int?
  2. 這些迭代器指向什麼類型?

謝謝!

+1

您能否清楚地說明您如何定義數據包結束? – 2010-01-03 00:17:26

回答

1

樣品匹配函數被呈現在文檔。

std::pair<iterator, bool> 
match_whitespace(iterator begin, iterator end) 
{ 
    iterator i = begin; 
    while (i != end) 
    if (std::isspace(*i++)) 
     return std::make_pair(i, true); 
    return std::make_pair(i, false); 
} 

提領i這裏拉出一個字節。您需要提取足夠的字節以匹配int。

但請記住,回調不是read_until的唯一選項。其實這是最複雜的。你確定它不足以使用正則表達式嗎?

template< 
    typename AsyncReadStream, 
    typename Allocator, 
    typename ReadHandler> 
void async_read_until(
    AsyncReadStream & s, 
    boost::asio::basic_streambuf<Allocator> & b, 
    const boost::regex & expr, 
    ReadHandler handler); 

無論如何,考慮到你讀不delimeted,有很多更好的辦法是async_read_some直到你讀的大小,然後用讀至少async_read_some。

1

我具有非常相似的消息格式到你的(16位有效載荷長度,8位的數據包ID /類型,接着是有效負載對我來說)。我做了3階段讀取,並用一組函數指針來處理不同的事情。我一次使用boost :: asio :: async_read讀取已知數量。

這是我的代碼的簡化版本:

//call this to start reading a packet/message 
void startRead(boost::asio::ip::tcp::socket &socket) 
{ 
    boost::uint8_t *header = new boost::uint8_t[3]; 
    boost::asio::async_read(socket,boost::asio::buffer(header,3), 
     boost::bind(&handleReadHeader,&socket,header, 
     boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error)); 
} 
void handleReadHeader(boost::asio::ip::tcp::socket *socket, 
    boost::uint8_t *header, size_t len, const boost::system::error_code& error) 
{ 
    if(error) 
    { 
     delete[] header; 
     handleReadError(error); 
    } 
    else 
    { 
     assert(len == 3); 
     boost::uint16_t payLoadLen = *((boost::uint16_t*)(header + 0)); 
     boost::uint8_t type  = *((boost::uint8_t*) (header + 2)); 
     delete[] header; 
     //dont bother calling asio again if there is no payload 
     if(payLoadLen > 0) 
     { 
      boost::uint8_t *payLoad = new boost::uint8_t[payLoadLen]; 

      boost::asio::async_read(*socket,boost::asio::buffer(payLoad,payLoadLen), 
       boost::bind(&handleReadBody,socket, 
       type,payLoad,payLoadLen, 
       boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error)); 
     } 
     else handleReadBody(socket,type,0,0,0,boost::system::error_code()); 
    } 
} 
void handleReadBody(ip::tcp::socket *socket, 
    boost::uint8_t type, boost::uint8_t *payLoad, boost::uint16_t len, 
    size_t readLen, const boost::system::error_code& error) 
{ 
    if(error) 
    { 
     delete[] payLoad; 
     handleReadError(error); 
    } 
    else 
    { 
     assert(len == readLen); 
     //passes the packet to the appropriate function for the type 
     //you could also use a switch statement or whatever 
     //to get the next packet you must call StartRead again 
     //personally I choose to do this from the actaul handler 
     //themselves 
     handlePacket(type,payLoad,len,error); 
    } 
}