Begin/End パターンを使用した非同期サーバー

.NET Framework で実装されている Begin/End パターンを使ってサーバーを作ってみました。
今回はクライアントと接続するだけです。クライアントとの通信処理は実装していません。

using System;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;

namespace Samples
{
    /// <summary>
    /// Begin/End パターンを使った Tcp サーバー。
    /// </summary>
    class BeginEndListener
    {
        Socket listener;

        public BeginEndListener()
        {
            listener = null;
        }

        public void Start()
        {
            if (listener != null) // Start() -> Start() とかした場合
                throw new InvalidOperationException();

            Debug.WriteLine("Enter BeginEndListener::Start");
            try
            {
                listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                listener.Bind(new IPEndPoint(IPAddress.Loopback, 8081));
                listener.Listen(10);
            }
            catch (Exception e)
            {
                if (listener != null)
                    listener.Close();
                listener = null; // null に戻す
                Debug.WriteLine("Exception BeginEndListener::Start " + e.Message);
                // throw e; 投げてもいい。投げない場合は IsListening で確認
            }
            finally
            {
                if (listener != null)
                {
                    Debug.WriteLine(string.Format("Info listener#{0}", listener.GetHashCode()));
                    listener.BeginAccept(EndAccept, listener);
                }
                Debug.WriteLine("Exit BeginEndListener::Start");
            }
        }

        public void Stop()
        {
            if (listener == null)
                return;

            Debug.WriteLine("Enter BeginEndListener::Stop");
            listener.Close();
            listener = null;
            Debug.WriteLine("Exit BeginEndListener::Stop");
        }

        private void EndAccept(IAsyncResult ar)
        {
            Debug.WriteLine("Enter BeginEndListener::EndAccept");
            // if (IsListening) return; とかはしない。同期とるよりも listener が閉じられてたら例外を拾った方が簡単。
            Socket listener = ar.AsyncState as Socket; // 必ず呼び出した listener を使う
            Socket client = null;
            try
            {
                listener.BeginAccept(EndAccept, listener); // すぐに次へ
                client = listener.EndAccept(ar);
            }
            catch (Exception e)
            {
                if (e is ObjectDisposedException)
                    Debug.WriteLine(string.Format("Exception BeginEndListener::EndAccept listener({0}) is closed", listener.GetHashCode()));
                else
                    Debug.WriteLine("Exception BeginEndListener::EndAccept {0}", e.GetType().ToString());
            }
            finally
            {
                Debug.WriteLine("Exit BeginEndListener::EndAccept");

                // ここでクライアントと通信する。
                // とりあえず今回は閉じるだけ。
                if (client != null)
                    client.Close();

                // Connection conn = new Connection(client)
                // while (conn.Connected)
                // {
                //     HandleRequest(conn);
                // }
            }
        }
    }
}