web-dev-qa-db-ja.com

C#HttpListenerで複数のリクエストを処理する

基本的にHttpListenerとして機能するスレッドを生成する.NETWindowsサービスがあります。これは同期モードの例では正常に機能しています...

private void CreateLListener()
{
    HttpListenerContext context = null;
    HttpListener listener = new HttpListener();
    bool listen = true;

    while(listen)
    {
        try
        {
            context = listener.GetContext();
        }
        catch (...)
        {
            listen = false;
        }
        // process request and make response
    }
}

私が今抱えている問題は、複数のリクエストを処理し、それらを同時に、または少なくとも重複して応答させるためにこれが必要なことです。

さらに説明すると、クライアントは、リクエストヘッダープロパティRange bytes=0-を使用してメディアファイルをリクエストすることから始まるメディアプレーヤーアプリです。私が知る限り、これはメディアコンテナが何であるかを理解するために行われます。

'チャンク'を読み取った後(またはメディアタイプを確認するのに十分に読み取った場合)、Range bytes=X-Yを使用して(別のクライアントソケット番号から)別の要求を行います。この場合、Yは最初の応答で返されるContent-Lengthであり、Xはそれより250000バイト少ない(テストとしてIISを使用して検出))この段階では、最後のチャンクを取得しています。 '長さを測定するためのメディアタイムスタンプを取得できるかどうかを確認します。

それを読んだ後、Range bytes=0-(別のソケット番号から)で別の要求を行い、メディアファイルのストリーミングを適切に開始します。

ただし、クライアントのユーザーが「スキップ」操作を実行すると、いつでもRange bytes=Z-を使用して(さらに別のソケット番号から)別の要求を送信します。ここで、Zはメディアファイル内でジャンプする位置です。

私はHTTPのことはあまり得意ではありませんが、私が知る限り、元のHttpListenerがリスニングに戻ることを許可しながら、各要求/応答を処理するために複数のスレッドを使用する必要があります。たくさん検索してみましたが、合うモデルが見つかりません。

編集:

自分のニーズに合わせて調整できた次の例について、RickStrahlに謝辞と感謝の意を表します...

数行のコードで.NET 2.0アプリにWebサーバーを追加します

14
Squonk

BeginGetContextのより単純な代替手段が必要な場合は、メインスレッドでジョブを実行する代わりに、ThreadPoolでジョブをキューに入れるだけで済みます。そのようなように:

private void CreateLListener() {
    //....
    while(true) {
        ThreadPool.QueueUserWorkItem(Process, listener.GetContext());    
    }
}
void Process(object o) {
    var context = o as HttpListenerContext;
    // process request and make response
}
16
user1096188

複数のリクエストを処理できるようにするには、asyncメソッドを使用する必要があります。したがって、e BeginGetContextおよびEndGetContextメソッドを使用します。

見てください ここ

同期モデルは、クライアント要求の待機中にアプリケーションがブロックする必要があり、one*のみを処理する場合に適しています。一度にリクエストする*。同期モデルを使用して、クライアントが要求を送信するのを待機するGetContextメソッドを呼び出します。このメソッドは、HttpListenerContextオブジェクトが発生したときに処理するために、HttpListenerContextオブジェクトを返します。

11
Aliostad

あなたが将来ここにいて、async/awaitを使用して単一のスレッドで複数の同時リクエストを処理しようとしている場合。

public async Task Listen(string prefix, int maxConcurrentRequests, CancellationToken token)
{
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add(prefix);
    listener.Start();

    var requests = new HashSet<Task>();
    for(int i=0; i < maxConcurrentRequests; i++)
        requests.Add(listener.GetContextAsync());

    while (!token.IsCancellationRequested)
    {
        Task t = await Task.WhenAny(requests);
        requests.Remove(t);

        if (t is Task<HttpListenerContext>)
        {
            var context = (t as Task<HttpListenerContext>).Result;
            requests.Add(ProcessRequestAsync(context));
            requests.Add(listener.GetContextAsync());
        }
    }
}

public async Task ProcessRequestAsync(HttpListenerContext context)
{
    ...do stuff...
}
10
gordy