1

現在Boost.Asioを使ってhttpサーバーを作ろうとしていて、このHTTP Server 3のようにしました。

現在、リクエストを読んだだけで、常にOKメッセージを返します。したがって、特別なことや時間がかかることはありません。

私が遭遇した問題は、サーバーを 12 スレッド (16 コア @ 2.53GHz) で実行している場合、サーバーは毎秒約 200 ~ 300 のリクエストを処理することです。

C# で HttpListener を使用して同じことを行い、12 のスレッドで実行し、約 5000 ~ 7000 のリクエストを処理します。

Boost.Asioは一体何をしているのですか?

Visual Studio でインストルメンテーション プロファイリングを使用すると、次の「最も個別の作業を伴う関数」が得られます。

Name                         Exclusive Time %
GetQueuedCompletionStatus               44,46
std::_Lockit::_Lockit                   14,54
std::_Container_base12::_Orphan_all      3,46
std::_Iterator_base12::~_Iterator_base12 2,06

編集1:

if (!err) {
  //Add data to client request
  if(client_request_.empty())
    client_request_ = std::string(client_buffer_.data(), bytes_transferred);
  else
    client_request_ += std::string(client_buffer_.data(), bytes_transferred);
  //Check if headers complete
  client_headerEnd_ = client_request_.find("\r\n\r\n");
  if(client_headerEnd_ == std::string::npos) {
    //Headers not yet complete, read again
    client_socket_.async_read_some(boost::asio::buffer(client_buffer_),
        boost::bind(&session::handle_client_read_headers, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred)); 
  } else { 
    //Search Cookie 
    std::string::size_type loc=client_request_.find("Cookie"); 
    if(loc != std::string::npos) {
    //Found Cookie
    std::string::size_type locend=client_request_.find_first_of("\r\n", loc);
    if(locend != std::string::npos) {
      std::string lCookie = client_request_.substr(loc, (locend-loc));            loc = lCookie.find(": ");           if(loc != std::string::npos) {
        std::string sCookies = lCookie.substr(loc+2);
        std::vector<std::string> vCookies;
        boost::split(vCookies, sCookies, boost::is_any_of(";"));
        for (std::size_t i = 0; i < vCookies.size(); ++i) {
          std::vector<std::string> vCookie;
          boost::split(vCookie, vCookies[i], boost::is_any_of("="));
          if(vCookie[0].compare("sessionid") == 0) {
            if(vCookie.size() > 1) {
              client_sessionid_ = vCookie[1];
              break;
            }
          }
        }             }
    }         }
    //Search Content-Length
    loc=client_request_.find("Content-Length");
    if(loc == std::string::npos) {
      //No Content-Length, no Content? -> stop further reading
      send_bad_request();
      return;
    }
    else {
      //Parse Content-Length, for further body reading
      std::string::size_type locend=client_request_.find_first_of("\r\n", loc);
      if(locend == std::string::npos) {
        //Couldn't find header end, can't parse Content-Length -> stop further reading
        send_bad_request();
        return;
      }
      std::string lHeader = client_request_.substr(loc, (locend-loc));
      loc = lHeader.find(": ");
      if(loc == std::string::npos) {
        //Couldn't find colon, can't parse Content-Length -> stop further reading
        send_bad_request();
        return;
      }
      //Save Content-Length
      client_request_content_length_ = boost::lexical_cast<std::string::size_type>(lHeader.substr(loc+2));
      //Check if already read complete body
      if((client_request_.size()-(client_headerEnd_)) < client_request_content_length_) {
        //Content-Length greater than current body, start reading.
        client_socket_.async_read_some(boost::asio::buffer(client_buffer_),
            boost::bind(&session::handle_client_read_body, shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
      }
      else {
        //Body is complete, start handling
        handle_request();
      }
    }
  }
}

編集2:

テストに使用されるクライアントは、スリープなしで 1000 回反復するたびに 128 スレッドを開始する単純な C# アプリケーションです。

System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(BaseUrl);
req.Method = "POST";
byte[] buffer = Encoding.ASCII.GetBytes("{\"method\":\"User.Login\",\"params\":[]}");
req.GetRequestStream().Write(buffer, 0, buffer.Length);
req.GetRequestStream().Close();
4

3 に答える 3

2

client_request_.find("\r\n\r\n");ループごとに文字列の先頭から終了トークンを探して、繰り返し呼び出されているようです。開始位置の位置を使用します。などclient_request_.find("\r\n\r\n", lastposition);(bytes_transferred を使用)

ここで使用でき asycn_read_until( ,"\r\n\r\n");ます

またはasync_read、(一部ではなく)すべてを読み取る必要があります。

于 2014-05-30T09:12:43.407 に答える
0

HTTP サーバー 3 の例について。request_parserのソース コードを見てください。メソッドは解析/消費します。バッファからバイト単位でデータを取得し、各バイトで作業するのは、実際には最適ではありません。push_backなどを使用してstd::stringにプッシュします。ほんの一例です。

また、asio::strandを使用している場合は、ミューテックス t ロック「ストランド実装」を使用していることに注意してください。HTTP サーバーの場合、 asio::strandを簡単に削除できるので、これを行うことをお勧めします。ストランドにとどまりたい場合- ロックの遅延を避けるために、コンパイル時にこれらの定義を設定できます。

-DBOOST_ASIO_STRAND_IMPLEMENTATIONS=30000 -DBOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION
于 2013-08-29T10:10:19.793 に答える