ローカルPOP3サーバを作る(その3)

体調が戻ってきたので、ゆっくり再開します。
実験をしながらこのまま実装を続けそうなので、Form成時に作成するスレッドのメソッド名をmain_thread変更した。

private:
Pop3S^ pop3s;
Thread^ oThread;
private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
	 pop3s = gcnew Pop3S();
	 oThread = gcnew Thread( gcnew ThreadStart(pop3s, &Pop3S::main_thread ) );
	 oThread->Start();
}

で、前回の実装だと複数のTCP接続に対して対応が出来ていないので、複数の接続を受け付けるようにする。
まず、Pop3Sクラスを整備する。TcpListenerはスレッドセーフとの事なので、コンストラクタでStart()して問題ないはず。

public ref class Pop3S
{
public:
  Pop3S(void);
  ~Pop3S(void);
  void main_thread(void); // 接続を受け付けるメインスレッド
private:
  System::Net::Sockets::TcpListener^ server;

  System::Collections::Generic::List<Thread^>^ ThreadList; // 生成したスレッドのリスト
};

Pop3S::Pop3S(void)
{
  try {
    int port = 110;
    IPAddress^ localAddr = IPAddress::Parse( "127.0.0.1" );
    ThreadList = gcnew List<Thread^>(); // 生成したスレッドをListで管理する

    // TcpListener* server = new TcpListener(port);
    server = gcnew TcpListener(localAddr,port );

    // Start listening for client requests.
    server->Start();

  } catch (Exception ^e) {
    // 何も考えてない
  }
}

Pop3S::~Pop3S(void)
{
  // 状態によらず無条件に呼んで良いのか?
  server->Stop();
}

で肝心の、main_threadはこんな感じになった。殆ど確認していないが、List管理は失敗している予感がプンプンする。生成したスレッドが終了して開放されたのであれば、IsAliveで例外が発生するし、whileループしているのでガベージコレクションも働かないはず。ただ、実験/プロトタイプ/学習/趣味のプログラムなので問題ない。
Pop3Handlerの実体は来週にでもつくる。

// FindIndexで使うための条件関数
bool threadAlive(Thread^ t)
{
  bool x = !t->IsAlive; //スレッドが生きているか
  return x;
};

void Pop3S::main_thread(void)
{
  System::Net::Sockets::TcpClient^ client;
  try {
    while ( true ) {
      if (server->Pending()) {
        client = server->AcceptTcpClient();
        if (client->Connected) {
          Debug::WriteLine( "Connected!" );
          // ここでListに保存して別スレッドを生成する
          // 生成した別スレッドでpop3の通信を行う
          Pop3Handler^ lpop = gcnew Pop3Handler(client);
          Thread^ tThread = gcnew Thread( gcnew ThreadStart(lpop, &Pop3Handler::Pop3main ));

          // 終了したスレッドのListは上書きしてしまう
          int t = ThreadList->FindIndex(gcnew Predicate<Thread^>(threadAlive));
          if (t == -1) {
            ThreadList->Add(tThread);
          } else {
            ThreadList[t] = tThread;
          }
          tThread->Start();
        }
      }
    }
  } catch ( SocketException^ e ) {
    Debug::Write( e->Message );
  }
}