前の開発日記 | 次の開発日記 | 一覧 |
だんだんと日曜プログラマのような感じになって来ました。 平日は時間作るの難しいですね。 あまり試行錯誤している時間も無いので設計を結構厳密に行うようになりました。
マルチスレッドなプログラムを書こうとすると、プログラムの流れが非常に複雑になるため
バグも発生しやすくなります。
絶妙のタイミングでこのデータが変更された場合、スレッドで異常が起きるといったような
普段は起きなくても稀に起きるバグも存在します。
マルチスレッドを使うときはメッセージのやり取りを極力単純化するのが楽ではないかと思います。
例えばキューを使ってメッセージをやり取りし、キューの部分だけをしっかりとクリティカルセクション処理を
用いてマルチスレッド対応にすれば、他にはあまり気を使わなくてすみます。
シーケンス図を書いてみて、それが複雑な図になるようでしたら少し危険でしょう。
環境 | Visual C++ 6.0 |
MFCでは、非同期ソケットではなく同期ソケットを使う方法が一般的のようですが、
試しに非同期ソケットを使って見ました。
非同期ソケットとは、何か処理をしようとした場合、例えば受信処理としますと、
データが送られてくるまでずっと待ちつづける、というのは非同期ソケットです。
これに対し同期ソケットは、普段は何もしませんが、メッセージが送られてくると
送られてくるきたことが分かるため、そこで初めて受信処理を行ってデータを受け取ります。
こういった事情があるため、今回扱う非同期ソケットは、ソケットの関数を呼ぶといつ戻ってくるか分かりません。
GUIでこのようなソケットを扱うと、メッセージループが回らなくなるため
外からはフリーズしたように見えます。
ですので、必ずスレッドを作り、その内部で扱う必要があります。
今回はスレッドの作り方については扱いません。
使用するクラスはCAsyncSocketです。まずはCreateします。 そのままでは同期ソケットですので、次にそれを非同期ソケットにします。
CAsyncSocket* lpSocket = new CAsyncSocket(); if (!lpSocket->Create(0, SOCK_STREAM, 0))return FALSE; // ●非同期モードに設定● DWORD blocking = FALSE; if (!lpSocket->IOCtl(FIONBIO, &blocking))return FALSE;
これで非同期モードになりました。後は普通にConnect,Receive,Sendを使うだけです。 OnConnectやOnReceive、等は使う必要がありません。使っても呼び出されません。
このソケットを、スレッド外部から終了させる方法も説明します。 これは、例えばユーザが中止ボタンを押したときのような場合です。
lpSocket->ShutDown(CAsyncSocket::both);
これで、本来の送受信用スレッドのソケット呼び出しはエラー終了します。 あとはそれを受けて本来のスレッドでCloseするだけです。 ShutDownではなくCloseを呼び出すと、CAsyncSocketクラスの内部でASSERTしてしまいますので注意しましょう。 なお、私は上記lpSocketを、スレッドクラスのメンバ変数にして使いました。
結局、非同期ソケットは、少し使い難い感じがしました。 CSocketクラスという、同期ソケットをまるで非同期のように扱うクラスが用意されてますので、 これを使うのが楽かもしれませんね。 しかし、CSocketは内部でよく分からない複雑な処理をやっているので、 ソケットは全て自分で管理したいという方には非同期ソケットはお勧めです。 (CAsyncSocketもそれなりに色々なことをやってはいるようですが・・・)
前の開発日記 | 次の開発日記 | 一覧 |