7

ブースト asio に基づいてプロキシ サーバーを作成しています。ブラウザからプロキシ サーバーへの着信接続の受け入れを担当するコードの一部で、完全には理解できない動作に直面しています。

だから - 私は次のコンストラクターでアクセプターオブジェクトを作成しています:

_acceptor(_io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port ), true)

ここで聞き始めます (start_accept):

_new_connection.reset(new connection(*_io_services.front(), _connection_id));
_acceptor.async_accept(_new_connection->get_socket(),
                            boost::bind(&server::handle_accept, this,
                                        boost::asio::placeholders::error));

および handle_accept

if (!error) {
    _new_connection->start();
}

// continue waiting for incoming connections
start_accept();

一般に、着信接続を受け入れるための私のコードは、 HTTP Server 2の例と同じです

この問題は、最初の着信接続が閉じられていない場合にのみ発生し、最初の着信接続が閉じられるまで、2 番目の着信がキューに入れられて保留されます。

この 2 つの回答によると、 boost::asio アクセプターの再開と EOF 後の非同期読み取り

Boost::asio tcp サーバーが起動したばかりのときに「イベント」を起動する方法 (別名 io_service.run() )?

アクセプター オブジェクトはすべての着信接続をキューに追加し、保留中の接続が閉じられなくなるまでそれらを受け入れません。

すべての着信接続をすぐに処理したいので、アクセプターのキューで保留されていないため、これまでのところ解決策が見つかりませんでした。

これを実装する正しい方法は何ですか?

connection->start() 関数

void
connection::start() {
    _bsocket.async_read_some(boost::asio::buffer(_bbuffer),
            boost::bind(&connection::handle_browser_read_headers,
                        shared_from_this(),
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
        ));
}

グラフィカルな表現 の更新: asio ログのブースト

@asio|1368460995.389629|0*1|socket@00CCFBE4.async_accept
@asio|1368461003.855113|>1|ec=system:0
@asio|1368461003.855113|1*2|socket@00E26850.async_receive
@asio|1368461003.855113|>2|ec=system:0,bytes_transferred=318
@asio|1368461003.856113|1*3|socket@00CCFBE4.async_accept
@asio|1368461003.856113|<1|
@asio|1368461003.856113|2*4|resolver@00E268D8.async_resolve
@asio|1368461003.856113|<2|
@asio|1368461003.866114|>4|ec=system:0,...
@asio|1368461003.866114|4*5|socket@00E26894.async_connect
@asio|1368461003.868114|<4|
@asio|1368461004.204133|>5|ec=system:0
@asio|1368461004.204133|5*6|socket@00E26894.async_send
@asio|1368461004.204133|<5|
@asio|1368461004.204133|>6|ec=system:0,bytes_transferred=302
@asio|1368461004.204133|6*7|socket@00E26894.async_receive
@asio|1368461004.204133|<6|
@asio|1368461004.613156|>7|ec=system:0,bytes_transferred=16384
@asio|1368461004.613156|7*8|socket@00E26850.async_send
@asio|1368461004.614157|<7|
@asio|1368461004.614157|>8|ec=system:0,bytes_transferred=16384
@asio|1368461004.614157|8*9|socket@00E26894.async_receive
@asio|1368461004.614157|<8|
@asio|1368461004.614157|>9|ec=system:0,bytes_transferred=1946
@asio|1368461004.614157|9*10|socket@00E26850.async_send
@asio|1368461004.614157|<9|
@asio|1368461004.614157|>10|ec=system:0,bytes_transferred=1946
@asio|1368461004.614157|10*11|socket@00E26894.async_receive
@asio|1368461004.614157|<10|
@asio|1368461004.618157|>11|ec=system:0,bytes_transferred=14080
@asio|1368461004.618157|11*12|socket@00E26850.async_send
@asio|1368461004.619157|<11|
@asio|1368461004.619157|>12|ec=system:0,bytes_transferred=14080
@asio|1368461004.619157|12*13|socket@00E26894.async_receive
@asio|1368461004.619157|<12|
@asio|1368461019.248994|>13|ec=asio.misc:2,bytes_transferred=0
@asio|1368461019.248994|13|socket@00E26894.close
@asio|1368461019.248994|13|socket@00E26850.close
@asio|1368461019.248994|<13|
@asio|1368461019.253994|0|resolver@00E268D8.cancel
@asio|1368461019.253994|>3|ec=system:0
@asio|1368461019.253994|3*14|socket@00E32688.async_receive
@asio|1368461019.254994|3*15|socket@00CCFBE4.async_accept
@asio|1368461019.254994|<3|
@asio|1368461019.254994|>14|ec=system:0,bytes_transferred=489
@asio|1368461019.254994|14*16|resolver@00E32710.async_resolve
@asio|1368461019.254994|<14|
@asio|1368461019.281995|>16|ec=system:0,...
@asio|1368461019.281995|16*17|socket@00E326CC.async_connect
@asio|1368461019.282996|<16|
@asio|1368461019.293996|>17|ec=system:0
@asio|1368461019.293996|17*18|socket@00E326CC.async_send
@asio|1368461019.293996|<17|
@asio|1368461019.293996|>18|ec=system:0,bytes_transferred=470
@asio|1368461019.293996|18*19|socket@00E326CC.async_receive
@asio|1368461019.293996|<18|
@asio|1368461019.315997|>19|ec=system:0,bytes_transferred=11001
@asio|1368461019.315997|19*20|socket@00E32688.async_send
@asio|1368461019.349999|<19|
@asio|1368461019.349999|>20|ec=system:0,bytes_transferred=11001
@asio|1368461019.349999|20|socket@00E326CC.close
@asio|1368461019.349999|20|socket@00E32688.close
@asio|1368461019.349999|<20|
@asio|1368461019.349999|0|resolver@00E32710.cancel

アクセプターの動作は、サーバー ソケットからのデータの読み取りに使用している関数に依存することがわかりました。接続クラスは、ブラウザーからデータを読み取り、要求 URL を変更し、ホストに接続して要求を送信し、サーバーから応答を読み取り、それをブラウザーに書き戻します。したがって、サーバー本体を読み取る必要があるときは、この関数を使用します

    _ssocket.async_read_some(boost::asio::buffer(_sbuffer),
            boost::bind(&connection::handle_server_read_body,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred
        ));

サービス応答ヘッダーで content-length が指定されていない場合、EOF まで読み取ります。async_read_some 関数が呼び出され、ソケットに読み取るデータがない場合、EOF が発生するまで約 15 秒待機します。この 15 秒間のすべての新しい着信接続は、アクセプターによって受け入れられません。

しかし、async_read の別のバリアントを使用している場合 -

        boost::asio::async_read(_ssocket, boost::asio::buffer(_sbuffer),
            boost::bind(&connection::handle_server_read_body,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred
        ));

着信接続は問題なく受け入れられます。しかし、boost::asio::async_read の動作は少し遅く、大量のデータがソケットから読み取られるのを待っており、そのデータが読み取られるまでハンドラーを呼び出さないため、transfer_at_least を指定すると思いました

        boost::asio::async_read(_ssocket, boost::asio::buffer(_sbuffer), boost::asio::transfer_at_least(1),
            boost::bind(&connection::handle_server_read_body,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred
        ));

ええ、それは良くなりました-しかし、新しい接続を受け入れる際の問題が返されます:/

async_read_some と boost::asio::async_read の本当の違いは何ですか - 何かがブロックされているように感じます。

4

1 に答える 1

0

これが役立つかどうかはわかりませんが、私のサーバーでは、セッションの読み取り要求に次を使用しています。

boost::asio::async_read( socket(), boost::asio::buffer( _incoming ),
    boost::asio::transfer_at_least( 1 ),
    boost::bind( &server_class::handle_read, shared_from_this(),
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred ) );

次に、受け取ったものをパーサーにダンプして、正常であることを確認します (処理状態など)。

そうでなければ、私がここで見たものに基づいて、私はあなたがしていることをすべてやっていると信じています.

これが機能する場合、asio は直感的ではない動作をしているように見えます。

于 2013-05-21T20:44:12.190 に答える