3

Boost ASIO exampleを変更して、単純な HTTPS サーバーを作成しようとしています。動作しますが、問題は、クライアントからの要求ごとに安全な接続を確立することであり、これにより通信が大幅に遅くなります。

HTTPS サーバーが Keep-Alive 接続を使用する必要があることはわかっています。しかし、上記の例を拡張してそれを行う方法がわかりません。私の場合、状況は非常に単純です。私は常に 1 対 1 で接続しているため、セッション管理は必要ありません。有効なセッションは常に 1 つだけです。

私は 2 種類の HTTP 応答を使用します。

std::string HTTPS::createResponse(status_type status)
{
    std::stringstream response;
    response<<statusCodeToString(status);
    response<<"Content-Length: "<<statusToContentString(status).size()<<"\r\n";
    response<<"Content-Type: text/html\r\n\r\n";
    response<<statusToContentString(status);

    return response.str();
}

std::string HTTPS::createResponse(status_type status, const std::string &data)
{
    std::stringstream response;
    response<<"HTTP/1.1 200 OK\r\n";
    response<<"Content-Length: "<<data.size()<<"\r\n";
    response<<"Content-Type: text/plain\r\n\r\n";
    response<<data;

    return response.str();
}

std::string HLSProxyServerSSL::statusCodeToString(status_type status)
{
    static const char ok_s[] =
        "HTTP/1.1 200 OK\r\n";
    static const char created_s[] =
        "HTTP/1.1 201 Created\r\n";
    static const char accepted_s[] =
        "HTTP/1.1 202 Accepted\r\n";
    static const char no_content_s[] =
        "HTTP/1.1 204 No Content\r\n";
    static const char multiple_choices_s[] =
        "HTTP/1.1 300 Multiple Choices\r\n";
    static const char moved_permanently_s[] =
        "HTTP/1.1 301 Moved Permanently\r\n";
    static const char moved_temporarily_s[] =
        "HTTP/1.1 302 Moved Temporarily\r\n";
    static const char not_modified_s[] =
        "HTTP/1.1 304 Not Modified\r\n";
    static const char bad_request_s[] =
        "HTTP/1.1 400 Bad Request\r\n";
    static const char unauthorized_s[] =
        "HTTP/1.1 401 Unauthorized\r\n";
    static const char forbidden_s[] =
        "HTTP/1.1 403 Forbidden\r\n";
    static const char not_found_s[] =
        "HTTP/1.1 404 Not Found\r\n";
    static const char not_supported_s[] =
        "HTTP/1.1 405 Method Not Supported\r\n";
    static const char not_acceptable_s[] =
        "HTTP/1.1 406 Method Not Acceptable\r\n";
    static const char internal_server_error_s[] =
        "HTTP/1.1 500 Internal Server Error\r\n";
    static const char not_implemented_s[] =
        "HTTP/1.1 501 Not Implemented\r\n";
    static const char bad_gateway_s[] =
        "HTTP/1.1 502 Bad Gateway\r\n";
    static const char service_unavailable_s[] =
        "HTTP/1.1 503 Service Unavailable\r\n";

    switch (status)
    {
        case ok:
            return ok_s;
        case created:
            return created_s;
        case accepted:
            return accepted_s;
        case no_content:
            return no_content_s;
        case multiple_choices:
            return multiple_choices_s;
        case moved_permanently:
            return moved_permanently_s;
        case moved_temporarily:
            return moved_temporarily_s;
        case not_modified:
            return not_modified_s;
        case bad_request:
            return bad_request_s;
        case unauthorized:
            return unauthorized_s;
        case forbidden:
            return forbidden_s;
        case not_found:
            return not_found_s;
        case not_supported:
            return not_supported_s;
        case not_acceptable:
            return not_acceptable_s;
        case internal_server_error:
            return internal_server_error_s;
        case not_implemented:
            return not_implemented_s;
        case bad_gateway:
            return bad_gateway_s;
        case service_unavailable:
            return service_unavailable_s;
        default:
            return internal_server_error_s;
    }
}

std::string HLSProxyServerSSL::statusToContentString(status_type status)
{
    static const char ok_s[] = "";
    static const char created_s[] =
        "<html>"
        "<head><title>Created</title></head>"
        "<body><h1>201 Created</h1></body>"
        "</html>";
    static const char accepted_s[] =
        "<html>"
        "<head><title>Accepted</title></head>"
        "<body><h1>202 Accepted</h1></body>"
        "</html>";
    static const char no_content_s[] =
        "<html>"
        "<head><title>No Content</title></head>"
        "<body><h1>204 Content</h1></body>"
        "</html>";
    static const char multiple_choices_s[] =
        "<html>"
        "<head><title>Multiple Choices</title></head>"
        "<body><h1>300 Multiple Choices</h1></body>"
        "</html>";
    static const char moved_permanently_s[] =
        "<html>"
        "<head><title>Moved Permanently</title></head>"
        "<body><h1>301 Moved Permanently</h1></body>"
        "</html>";
    static const char moved_temporarily_s[] =
        "<html>"
        "<head><title>Moved Temporarily</title></head>"
        "<body><h1>302 Moved Temporarily</h1></body>"
        "</html>";
    static const char not_modified_s[] =
        "<html>"
        "<head><title>Not Modified</title></head>"
        "<body><h1>304 Not Modified</h1></body>"
        "</html>";
    static const char bad_request_s[] =
        "<html>"
        "<head><title>Bad Request</title></head>"
        "<body><h1>400 Bad Request</h1></body>"
        "</html>";
    static const char unauthorized_s[] =
        "<html>"
        "<head><title>Unauthorized</title></head>"
        "<body><h1>401 Unauthorized</h1></body>"
        "</html>";
    static const char forbidden_s[] =
        "<html>"
        "<head><title>Forbidden</title></head>"
        "<body><h1>403 Forbidden</h1></body>"
        "</html>";
    static const char not_found_s[] =
        "<html>"
        "<head><title>Not Found</title></head>"
        "<body><h1>404 Not Found</h1></body>"
        "</html>";
    static const char not_supported_s[] =
        "<html>"
        "<head><title>Method Not Supported</title></head>"
        "<body><h1>Method Not Supported</h1></body>"
        "</html>";
    static const char not_acceptable_s[] =
        "<html>"
        "<head><title>Request Not Acceptable</title></head>"
        "<body><h1>Request Not Acceptable</h1></body>"
        "</html>";
    static const char internal_server_error_s[] =
        "<html>"
        "<head><title>Internal Server Error</title></head>"
        "<body><h1>500 Internal Server Error</h1></body>"
        "</html>";
    static const char not_implemented_s[] =
        "<html>"
        "<head><title>Not Implemented</title></head>"
        "<body><h1>501 Not Implemented</h1></body>"
        "</html>";
    static const char bad_gateway_s[] =
        "<html>"
        "<head><title>Bad Gateway</title></head>"
        "<body><h1>502 Bad Gateway</h1></body>"
        "</html>";
    static const char service_unavailable_s[] =
        "<html>"
        "<head><title>Service Unavailable</title></head>"
        "<body><h1>503 Service Unavailable</h1></body>"
        "</html>";

    switch (status)
    {
        case ok:
            return ok_s;
        case created:
            return created_s;
        case accepted:
            return accepted_s;
        case no_content:
            return no_content_s;
        case multiple_choices:
            return multiple_choices_s;
        case moved_permanently:
            return moved_permanently_s;
        case moved_temporarily:
            return moved_temporarily_s;
        case not_modified:
            return not_modified_s;
        case bad_request:
            return bad_request_s;
        case unauthorized:
            return unauthorized_s;
        case forbidden:
            return forbidden_s;
        case not_found:
            return not_found_s;
        case not_supported:
            return not_supported_s;
        case not_acceptable:
            return not_acceptable_s;
        case internal_server_error:
            return internal_server_error_s;
        case not_implemented:
            return not_implemented_s;
        case bad_gateway:
            return bad_gateway_s;
        case service_unavailable:
            return service_unavailable_s;
        default:
            return internal_server_error_s;
        }
}

回答は問題ないと思いますが、確認してください。それは私の専門分野ではありません。

通信フローは次のとおりです。

1、サーバーは新しい接続の受け入れを開始します。セッションを作成し、ハンドシェイクの着信要求を待機する非同期アクセプターをバインドします。

2、着信ハンドシェイクが発生すると、サーバーはポイント1で作成されたセッションでハンドシェイクを開始します。

3、ハンドシェイクが完了すると、受信メッセージを処理します

セッション ハンドシェイク ハンドルは次のとおりです。1 つの HTTP コマンドを読み取り、処理します。サーバー側からは GET コマンドのみが有効であるため、ヘッダーの残りの部分は意図的に気にしません。サーバーは単純な再送信者のように機能します。

void SSLSession::handleHandshake(const boost::system::error_code& error)
{
    __log_print(LOG_INFO, "SSLSession", "handleHandshake");

    if (!error)
    {
        boost::asio::async_read_until(_socket, _data, "\r\n", boost::bind(&SSLSession::handleHttpRequestLine, this, _1));
    }
    else
    {
        delete this;
    }
}

void SSLSession::handleHttpRequestLine(boost::system::error_code ec)
{
    std::string method, uri, version;

    if (!ec)
    {
        char sp1, sp2, cr, lf;
        std::istream is(&_data);
        is.unsetf(std::ios_base::skipws);
        is >> method >> sp1 >> uri >> sp2 >> version >> cr >> lf;
    }

    handleHttpRequest(method, uri);
}

だから私の質問は、どうすればメソッドを変更できますか:

void SSLSession::handleHandshake(const boost::system::error_code& error)

開始するには、1 つのコマンドだけでなく、このセッションで有効な継続的に受信する GET コマンドをリッスンしますか? もう一つ追加してみました

boost::asio::async_read_until(_socket, _data, "\r\n", boost::bind(&SSLSession::handleHttpRequestLine, this, _1));

メソッドの最後に呼び出しますhandleHttpRequest(method, uri);が、デッドロックが発生しました...些細なことに違いないと思いますが、これらすべての非同期アクセプターとハンドラーで迷っています...

4

1 に答える 1

3

着信GETコマンドを継続的にリッスンするための最も簡単な解決策は、async_read_untilを処理するチェーン内から操作を開始することasync_read_untilです。コード例では、それを使用することhandleHttpRequestは実行可能なオプションのように聞こえます。

非同期呼び出しチェーンで迷子になっている場合は、それらを説明することを検討してください。

void SSLSession::handleHandshake(...)
{
  if (!error)
  {
    boost::asio::async_read_until(...);  ----.
  }                                          |
}              .-----------------------------'
               |  .--------------------------.                     
               v  v                          |
void SSLSession::handleHttpRequestLine(...)  |
{                                            |
  handleHttpRequest(...); --.                |
}                           |                |
               .------------'                |
               v                             |
void SSLSession::handleHttpRequest(...)      |
{                                            |
  boost::asio::async_read_until(...);  ------'
}

Boost.Asio 1.47+ の場合、チェーンをデバッグするためのもう 1 つの優れたオプションは、ハンドル トラッキングを有効にすることです。定義するだけBOOST_ASIO_ENABLE_HANDLER_TRACKINGで、Boost.Asio はタイムスタンプを含むデバッグ出力を標準エラー ストリームに書き込みます。 この回答では、ハンドラのデバッグについて詳しく説明しています。

デッドロックが発生している場合は、アプリケーション コードにある可能性があります。ほとんどの Boost.Asio 型では、オブジェクトで複数の非同期操作を保留しても問題ありません。オブジェクトの同時呼び出しは安全でないと指定されているだけです。ただし、通常、 などの一部のタイプでは問題になりませんip::tcp::socket。ただし、次のことをssl::stream強調します。

また、アプリケーションは、すべての非同期操作が同じ暗黙的または明示的なストランド内で実行されるようにする必要があります。

この質問に示されているように、未定義の動作が発生する可能性があり、デッドロックが発生する可能性があります。複数のスレッドがio_serviceイベント ループを処理している場合は、非同期操作を で実行することを検討してboost::asio::strandください。

于 2013-04-08T02:01:06.330 に答える