2012-03-29 2 views
0

私はに新規登録しました。boost :: asioだから私の質問には愚かなことがあります。 キープアライブを使用して非同期サーバーアプリケーションを作成しています(1回の接続で複数の要求が送信されることがあります)。boost :: asio basic_stream_socket :: async_read_someハンドラのデータの一部のみを消費します。

  • スケジュールハンドラスケジュールからsocket-> async_read_some(バッファ、ハンドラ)

  • と読み出し要求:

    ループにおいて:

    接続処理ルーチンは単純です書き込み応答はasync_writeです。

私が直面しています問題はasync_read_someに渡さ ハンドラは上のio_serviceスレッドによって呼び出されたときに、バッファが実際に単一の要求よりも多くのデータ(の例えば一部を含んでいてもよいことですクライアントから送信された次の要求)。

この残りのバイトは現時点では処理したくありません(要求の一部に過ぎない場合は処理できません)。 前のリクエストが処理された後にやりたいと思います。

不要なリマイニングデータをソケットに再投入する可能性がある場合は、この問題に対処するのは簡単です。したがって、それはのasync_read_someコールで処理されます。

ブーストでこのようなpossiblityは:: ASIOありますか私はどこかはさておき、残りのデータを格納する必要があり、余分なコードでそれを自分自身を処理します。

答えて

4

TCPのような信頼性と注文したトランスポートを使用している場合、これを取り組む一つの方法は、以下のとおりです。

  1. が残りを書くメッセージ
  2. の残りの部分のサイズを含む、既知のサイズのヘッダを書きますメッセージ

そして、受信側:

  1. 読む彼を取得するだけの十分なバイトADER
  2. あなたはメッセージが固定長であることを行っているわかっている場合は、次のような何かを行うことができ、メッセージの残りの部分とこれ以上
+0

プロトコルが固定されていると私はそれを変更することはできません残念ながら、これは現実的ではありません:( – losipiuk

+0

@losipiukを使用すると、プロトコルことを言っているので:クライアントとしてHTTPヘッダを解析するコードの例を作業する

現在のフォームにはメッセージのサイズを示すメタデータが含まれていませんメッセージの開始区切り文字と終了区切り文字がありますかメッセージが実際には完全であると判断していますか – hatboyzero

+0

いいえ - 固定サイズはありませんヘッダー。実際にはHTTPです。 – losipiuk

1

を読む:

//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ 
void 
Connection::readMore() 
{ 
    if (m_connected) 
    { 
     // Asynchronously read some data from the connection into the buffer. 
     // Using shared_from_this() will prevent this Connection object from 
     // being destroyed while data is being read. 
     boost::asio::async_read(
      m_socket, 
      boost::asio::buffer(
       m_readMessage.getData(), 
       MessageBuffer::MESSAGE_LENGTH 
      ), 
      boost::bind(
       &Connection::messageBytesRead, 
       shared_from_this(), 
       boost::asio::placeholders::error, 
       boost::asio::placeholders::bytes_transferred 
      ), 
      boost::bind(
       &Connection::handleRead, 
       shared_from_this(), 
       boost::asio::placeholders::error 
      ) 
     ); 
    } 
} 

//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ 
std::size_t 
Connection::messageBytesRead(const boost::system::error_code& _errorCode, 
          std::size_t _bytesRead) 
{ 
    return MessageBuffer::MESSAGE_LENGTH - _bytesRead; 
} 

//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ 
void 
Connection::handleRead(const boost::system::error_code& _errorCode) 
{ 
    if (!_errorCode) 
    { 
     /// Do something with the populated m_readMessage here. 
     readMore(); 
    } 
    else 
    { 
     disconnect(); 
    } 
} 

messageBytesRead完全なメッセージが読み込まれたときにコールバックはboost::asio::async_readになります。このスニペットは、実行中のコードから既存のConnectionオブジェクトから取得されたので、動作することがわかりました...

5

あなたが探しているものはasio::streambufだと思います。

基本的に、あなたは、char型の*としてあなた播種したstreambufを検査し、あなたが合うようにできるだけ多くを読み、[consume(amount)によって処理され、実際にたどのくらい知らせることができます。

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

namespace asio = boost::asio; 

std::string LINE_TERMINATION = "\r\n"; 

class Connection { 
    asio::streambuf _buf; 
    asio::ip::tcp::socket _socket; 
public: 

    Connection(asio::io_service& ioSvc, asio::ip::tcp::endpoint server) 
    : _socket(ioSvc) 
    { 
    _socket.connect(server); 
    _socket.send(boost::asio::buffer("GET/HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")); 
    readMore(); 
    } 

    void readMore() { 
    // Allocate 13 bytes space on the end of the buffer. Evil prime number to prove algorithm works. 
    asio::streambuf::mutable_buffers_type buf = _buf.prepare(13); 

    // Perform read 
    _socket.async_read_some(buf, boost::bind(
      &Connection::onRead, this, 
      asio::placeholders::bytes_transferred, asio::placeholders::error 
    )); 
    } 

    void onRead(size_t read, const boost::system::error_code& ec) { 
    if ((!ec) && (read > 0)) { 
     // Mark to buffer how much was actually read 
     _buf.commit(read); 

     // Use some ugly parsing to extract whole lines. 
     const char* data_ = boost::asio::buffer_cast<const char*>(_buf.data()); 
     std::string data(data_, _buf.size()); 
     size_t start = 0; 
     size_t end = data.find(LINE_TERMINATION, start); 
     while (end < data.size()) { 
     std::cout << "LINE:" << data.substr(start, end-start) << std::endl; 
     start = end + LINE_TERMINATION.size(); 
     end = data.find(LINE_TERMINATION, start); 
     } 
     _buf.consume(start); 

     // Wait for next data 
     readMore(); 
    } 
    } 
}; 

int main(int, char**) { 
    asio::io_service ioSvc; 

    // Setup a connection and run 
    asio::ip::address localhost = asio::ip::address::from_string("127.0.0.1"); 
    Connection c(ioSvc, asio::ip::tcp::endpoint(localhost, 80)); 

    ioSvc.run(); 
} 
+1

+1これは必要なものと同じように聞こえます。 – sje397

+0

私はASIO-helpのために自分自身(他の似たようなニーズのために)を探していて、これを見つけました: http://think-async.com/Asio/boost_asio_1_3_1/doc/html/boost_asio/overview/core/line_based .html – Rawler

関連する問題