HttpListenerについて
お世話になっております。
今System.Net.HttpListenerを使用して通信しようとしているのですが、こいつの動作が分かりにくいので実験します。
サーバーを開始するには、以下の手順を実行します。
上記4につきましては、今回はコールバックによる実装としました。このときのポイントとしては、BeginGetContextの第二パラメータにHttpListenerのインスタンスを渡すことです。コールバックメソッドから、HttpListener.IsListeningを参照するには、これがベストな方法かと考えます。
次に、受信時の処理です。今回は、単純なエコーバック+試験用のスリープのみです。コールバックメソッド全体をlockしているのは、こうしないと処理中(今回はスリープ中)にも関わらず、HttpListenerを停止すると接続を切断してしまうからです。クライアントで切断に対応する実装方法もありますが、今回はわかりやすくするためにlockするようにしました。
最後に、サーバーの停止です。サーバーの停止には、以下4つのメソッドがあります。
- HttpListener.Abort Method (System.Net) | Microsoft Docs
- HttpListener.Close Method (System.Net) | Microsoft Docs
- HttpListener.Stop Method (System.Net) | Microsoft Docs
- HttpListener.IDisposable.Dispose Method (System.Net) | Microsoft Docs
まず、4は「not intended to be used directly from your code.」とありますので、使えません。残りのメソッドは、状況に応じて使い分けます。
以上で実装は完了です。Enterキー入力でサーバーを停止します。スリープ中にEnterを押した時は、応答の送信が完了してから終了します。
ただ。サーバーが停止するときにコールバックが動作するパターンと動作しないパターンがあります。この点はまだ不明です。
以下、コードです。
using System; using System.Net; using System.IO; using System.Threading; using System.Diagnostics; namespace Http { // 試験用HTTPサーバー public sealed class HttpServer { private HttpListener listener; private readonly object lockObj = new object(); // HttpListenerのインスタンスを作成する。 // Prefixをセットする。 // public void Start() { lock(this.lockObj){ this.listener = new HttpListener(); this.listener.Prefixes.Add("http://*:9999/"); this.listener.Start(); this.listener.BeginGetContext(this.OnRequested, this.listener); } } // 要求待ちを終了する。 public void Stop() { lock(this.lockObj) { this.listener.Close(); } } // 要求を受信した時に実行するメソッド。 public void OnRequested(IAsyncResult result){ lock(this.lockObj){ Debug.Assert(result != null, "result is not null."); HttpListener listener = (HttpListener)result.AsyncState; if(!listener.IsListening){ Console.WriteLine("listening finished."); return; } Console.WriteLine("OnRequested start."); Console.WriteLine("OnRequested result.IsCompleted " + result.IsCompleted); Console.WriteLine("OnRequested result.CompletedSynchronously " + result.CompletedSynchronously); Console.WriteLine("OnRequested listener.IsListening " + listener.IsListening); HttpListenerContext ctx = listener.EndGetContext(result); HttpListenerRequest req = null; HttpListenerResponse res = null; StreamReader reader = null; StreamWriter writer = null; // 試験用のスリープ Thread.Sleep(10000); try{ req = ctx.Request; res = ctx.Response; reader = new StreamReader(req.InputStream); writer = new StreamWriter(res.OutputStream); string received = reader.ReadToEnd(); Console.WriteLine(received); writer.Write(received); writer.Flush(); }catch(Exception ex){ Console.WriteLine(ex.ToString()); }finally{ try{ if(null != writer) writer.Close(); if(null != reader) reader.Close(); if(null != res) res.Close(); }catch(Exception ex){ Console.WriteLine(ex.ToString()); } } listener.BeginGetContext(this.OnRequested, listener); } Console.WriteLine("OnRequested end"); Console.WriteLine(); } public static void Main(){ HttpServer server = new HttpServer(); server.Start(); Console.ReadLine(); server.Stop(); } } }
以上