4

通過する特定のリクエストをログに記録する単純なプロキシの構築に取り組んでいます。プロキシは、(プロジェクトのこの時点で) 通過するトラフィックに干渉する必要がないため、プロセス中に生の要求/応答の解析をできるだけ少なくしようとしています (要求と応答はプッシュされます)。プロキシの外でログに記録されるようにキューにオフにします)。

私のサンプルは正常に動作しますが、「応答」がいつ完了したかを確実に判断できないため、接続が必要以上に長く開いたままになっています。関連するコードは次のとおりです。

var request = getRequest(url);
byte[] buffer;
int bytesRead = 1;
var dataSent = false;
var timeoutTicks = DateTime.Now.AddMinutes(1).Ticks;

Console.WriteLine("   Sending data to address: {0}", url);
Console.WriteLine("   Waiting for response from host...");
using (var outboundStream = request.GetStream()) {
   while (request.Connected && (DateTime.Now.Ticks < timeoutTicks)) {
      while (outboundStream.DataAvailable) {
         dataSent = true;
         buffer = new byte[OUTPUT_BUFFER_SIZE];
         bytesRead = outboundStream.Read(buffer, 0, OUTPUT_BUFFER_SIZE);

         if (bytesRead > 0) { _clientSocket.Send(buffer, bytesRead, SocketFlags.None); }

         Console.WriteLine("   pushed {0} bytes to requesting host...", _backBuffer.Length);
      }

      if (request.Connected) { Thread.Sleep(0); }
   }
}

Console.WriteLine("   Finished with response from host...");
Console.WriteLine("   Disconnecting socket");
_clientSocket.Shutdown(SocketShutdown.Both);

私の質問は、ヘッダーを解析せずに応答が完了したことを簡単に伝える方法があるかどうかです。この応答は何でもかまいません (エンコード、暗号化、gzip など)。実際の応答をデコードして長さを取得し、ソケットを切断できるかどうかを判断する必要はありません。

4

3 に答える 3

3

David が指摘したように、接続は一定期間開いたままにしておく必要があります。クライアント側がそうしない限り (またはキープアライブ間隔が切れた場合)、接続を閉じないでください。

あなたはサーバーであり、リクエストで HTTP/1.1 を指定するのはクライアントであるため、HTTP/1.0 への変更は機能しません。確かに、HTTP/1.0 をバージョンとしてエラー メッセージを送信し、クライアントが 1.0 に変更されることを期待できますが、効率が悪いようです。

HTTP メッセージは次のようになります。

REQUEST LINE
HEADERS
(empty line)
BODY

応答がいつ完了したかを知る唯一の方法は、Content-Length ヘッダーを検索することです。リクエスト バッファで「Content-Length:」を検索し、すべてを改行まで抽出するだけです。(ただし、int に変換する前に見つかった値をトリミングします)。

もう 1 つの方法は、Web サーバーでパーサーを使用してすべてのヘッダーを取得することです。パーサーだけを使用するのは非常に簡単で、ライブラリーからは何も使用しないはずです。

更新:ここに、より優れたパーサーがあります: HttpParser.cs

于 2010-07-26T18:20:37.327 に答える
3

1.1 ではなく HTTP/1.0 リクエストを行う場合、サーバーは別のリクエストのために接続を開いたままにしておく必要がないため、接続が完了するとすぐに接続を閉じる必要があります。

それ以外に、最良の値を取得するには、応答のコンテンツ長ヘッダーを解析する必要があります。

于 2010-07-26T17:56:20.660 に答える
-1

ブロッキング IO と複数のスレッドを使用することが答えかもしれません。具体的には

using(var response = request.GetResponse())
using(var stream = response.GetResponseStream())
using(var reader = new StreamReader(stream)
  data = reader.ReadToEnd()

これはテキスト データ用ですが、バイナリの処理も同様です。

于 2010-07-26T17:55:53.730 に答える