acceptは、発動した段階でソフトウェアを停止し、相手がconnectでSYNを送信するまでWindowsメッセージを処理しなくなります。
分かりやすくいうと、acceptを発動した時、SYNを受け取る動作以外無効化します。
B

illsut:江ノ木 椎茸(https://pawoo.net/@shitakenoki

しかし、acceptしている間、画面が止まるゲームは嫌ですよね。市販のゲームは通信待機中でも画面上をキャラが動いているものです。

そこで思いつく手法が、非同期通知です。
つまり、順番を逆にするのです。acceptで待ち受けてから、SYNを受け取るのではなく、SYNを受け取ってから、acceptを発動するのです。

SYNを受け取ったかどうかを判定するには、Windowsではイベントを作成すればよいでしょう。
イベントとは、いくつかの状態を持つスイッチのような変数です。

まずイベントを宣言し、SYNを受けとった時、言い換えると、acceptが必要な時にイベントをONにします。イベントがONになったら、acceptを発動します。

とりあえずイベントを宣言してみましょう。


イベントを宣言するにはWSAEVENT型を使います。
実はWinSockにはverson1とverson2があり、今まではverson1で学習を進めてきました。
しかし、WSAEVENT型はWinSock2にて定義されているので、今後はwinsock2をインクルードして下さい。これ以降の学習には、WinSock2を使用します。

それに伴い、inet_addrが警告を出すようになるため、警告を回避するプラグマを3行目で書いています。実用的なアプリケーションではinet_ptonなどを使用して下さい。

14行目でWSAEVENT型のイベントを宣言しています。
26行目でイベントを初期化しています。WSACreateEventは引数を持ちません。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
続いてソケットとイベントを紐付けます。bindやconnectと同じノリです。
ソケットとイベントを紐付けるにはWSAEventSelectを使用します。

第一引数へは紐付けるソケットを、第二引数へはイベント変数を、第三引数へは検知するイベントの種類を指定します。
このプログラムの関数を実行すると、ソケットがacceptを要する動作を検知すると、イベント変数の状態を勝手にシグナル状態へ変化させます。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
次のコードを表示する前に、WaitForSingleObject関数の説明をしておきます。
WaitForSingleObject(判定するイベント, 何秒停止するか)

WaitForSingleObjectはイベントの状態を判定します。
指定したイベントがシグナル状態のとき、WAIT_OBJECT_0を返します。

WaitForSingleObjectはブロッキングを起こします。しかしその時間は第二引数で指定できます。
0を指定すると、ブロッキングを起こさず、イベント変数の状態を判定してすぐに処理を返します。
これを利用しましょう。


このプログラムではwhile(1)で無限ループを作成し、ひたすら文字列を出力しています。
それに加えてWaitForSingleObjectでイベントの状態を毎ループ判定しています。第二引数は0なので、WaitForSingleObjectがソフトウェアを止めることはありません。

WaitForSingleObjectWAIT_OBJECT_0を返した時、SYNが届いているのでacceptを実行してbreak;でループを脱出します。break;は直近のループから脱出します。
ループを脱した後はacceptにて実際のやり取りを行うソケットが返却されているので、それを利用して今まで通りパケットを受け取ります。その後、画面に表示してWinSockとプログラムの終了処理です。

このプログラムにhellohello2という文字列パケットを送ると、実行結果は次のようになります。
16


もしacceptがブロッキングを起こすと、NowLoadingと1回だけ表示してアプリケーションは停止していたでしょう。でも……SYNパケットを待っている間アプリケーションが止まるのは嫌ですよね……
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ちなみにacceptが一度発動すると、紐つけたイベントのシグナル状態は勝手に解除されます。

補足ですが、WaitForSingleObjectの第二引数は1秒につき10000を指定して下さい。INFINITEを指定すると、イベント変数がシグナル状態になるまで永久に待機します。

また、非同期通知の手法はコンソールアプリケーション、Windowsアプリケーションで違いがありません。なぜなら、Win32APIの機能を使っているからです。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ちなみにconnectもブロッキングを起こすので、FD_CONNECTを使って同じように非同期通知を使用して下さい。

Next【5限目】WinアプリとWinSock

【0限目】