5

単純なTCPサーバーの実装に問題があります。次のコードは、boost :: asioの例、正確には「HttpServer1」から抜粋したものです。

void connection::start() {
    socket_.async_read_some(
            boost::asio::buffer(buffer_),
            boost::bind(
                &connection::handle_read, shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
            )
        );
}
void connection::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred) {
        if (!e && bytes_transferred)    {
                std::cout << " " << bytes_transferred <<"b" << std::endl;
                data_.append(buffer_.data(), buffer_.data()+bytes_transferred);

                //(1) what here?                
                socket_.async_read_some(
                    boost::asio::buffer(buffer_), 
                    boost::bind(
                        &connection::handle_read, shared_from_this(),
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
                    )
                ); 

            }
            else// if (e != boost::asio::error::operation_aborted)
            {
                std::cout << data_ << std::endl;
                connection_manager_.stop(shared_from_this());
            }
        }

元のコードでbuffer_は、はリクエスト全体を保持するのに十分な大きさです。それは私が必要なものではありません。サイズを32バイトに変更しました。

サーバーはローカルホストのポート80でコンパイルしてリッスンするので、Webブラウザーを介してサーバーに接続しようとします。

ここで、ステートメント(1)がコメント化されている場合、要求の最初の32バイトのみが読み取られ、接続がハングします。Webブラウザは応答を待ち続けます、サーバーはそうします..私は何を知りません。

(1)がコメント化されていない場合、リクエスト全体が読み取られます(そして、appedされますdata_)が、停止することはありません-ブラウザでリクエストをキャンセルする必要があり、その後、else { }部分が実行されます-stdoutにリクエストが表示されます。

質問1:大きなリクエストをどのように処理する必要がありますか?
質問2:リクエストをどのようにキャッシュする必要がありますか(現在、バッファを文字列に追加しています)?
質問3:リクエストが終了したことをどのように確認できますか?HTTPには常に応答があるので、Webブラウザーはそれを待ち続け、接続を閉じませんが、サーバーは要求が終了したことをどのように知ることができますか(おそらく、要求を閉じるか、「200OK」と応答します)。

4

1 に答える 1

9

ブラウザが1360バイトのデータを送信するとasioし、32バイトしかないデータをバッファに読み込むと言います。次に、最初にそれを呼び出すと、ハンドラーは32バイトのデータ開始で呼び出されます。ここでコメント(1)すると、ブラウザは残りのデータを送信しようとします(実際には、ブラウザはすでにデータを送信しており、そこからのぞき見を待つのはOSバッファにあります)io_service::run

ループが開始したと言うときに(1)のコメントを外すと、最初のブロックを読み取り、次に次のブロックを読み取り、ブラウザが送信したデータが終了するまで...ブラウザが送信したデータが終了するまで読み取りますが、その後、asioさらにデータを読み取ると言うと、待機します。ブラウザから決して取得されないデータ(ブラウザはすでに情報を送信し、応答を待っているため)、ブラウザからのリクエストをキャンセルすると、ソケットが閉じられ、ハンドラーが呼び出され、次のようなエラーが発生します。接続が切断されているため、これ以上データを読み取ることができません。

しかし、それを機能させるためにここですべきことは、HTTPフォーマットを学び、ブラウザがあなたに送信したデータが何であるかを知って、それに良い答えを提供する必要があります。そうすれば、クライアントとのコミュニケーションが進みます。この場合、バッファの終わりはで\r\n\r\nあり、それを確認したら、それ以上データを読み取る必要はありません。これまでに読み取った内容を処理してから、ブラウザに応答を送信する必要があります。

于 2012-09-16T21:26:27.577 に答える