体調が戻ってきたので、ゆっくり再開します。
実験をしながらこのまま実装を続けそうなので、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 ); } }