非ブロッキングソケットのrecvについて
現在、Winsock2を使ってあるサーバーのプログラムを作成しています。
WSAEventSelect関数を使って非ブロッキングソケットを扱っているのですが、複数のクライアントからほぼ同時に接続要求などがあった際に
接続を取りこぼしてしまいます。
どなたかアドバイスいただけませんでしょうか。
以下、ソースを示します。プログラムの動作をわかりやすくするためエラー処理などは省略して記載します。(実際には行っています)
ちなみに非ブロッキングソケットを使用する理由は以下のとおりです。
・GUIアプリのワーカースレッドで動作させており、ブロッキングソケットでブロック中にメインスレッドが終了してもワーカースレッドがそれを知る術がなくワーカースレッドを安全に終了させることができないため。
/* 変数の宣言*/
int iRet=-1;
SOCKET ListenSock;
SOCKET AcceptSock;
int iRcvClientLen=0;
int iRcvLen=0;
char caRcvDat[1024]={0};
WSAEVENT hEvent;
DWORD dwResult;
WSANETWORKEVENTS events;
/* リッスンソケットを作成*/
ListenSock = socket(AF_INET, SOCK_STREAM, 0);
/* イベントのクリエイト*/
hEvent = WSACreateEvent();
/* リッスンソケットの設定*/
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NUM); /*PORT_NUMは定数*/
addr.sin_addr.S_un.S_addr = INADDR_ANY;
/* リッスンソケットをバインド*/
iRet = bind(ListenSock, (struct sockaddr *)&addr, sizeof(addr));
/* リッスンソケットでポートを開く*/
iRet = listen(ListenSock, 10);
/* クライアント接続待ちの無限ループ*/
while (1) {
printf("\n\n/--------- 待機中 ---------/\n\n");
iRcvClientLen = sizeof(client);
/* リッスンソケットにACCEPTイベントを設定*/
iRet = WSAEventSelect(ListenSock, hEvent, FD_ACCEPT);
/* ACCEPTイベント発生まで待機*/
dwResult = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE);
/* 発生したイベントを解析*/
iRet = WSAEnumNetworkEvents(ListenSock, hEvent, &events);
/* イベント変数をリセット*/
WSAResetEvent(hEvent);
/* 発生したイベントがACCEPTであれば接続を受け入れる*/
if(events.lNetworkEvents & FD_ACCEPT){
AcceptSock = accept(ListenSock, (struct sockaddr *)&client, &iRcvClientLen);
}
/* ACCEPTしたソケットにREADイベントを設定しなおす*/
iRet = WSAEventSelect(AcceptSock, hEvent, FD_READ);
/* READイベント発生まで待機*/
dwResult = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE);
/* 発生したイベントを解析*/
iRet = WSAEnumNetworkEvents(AcceptSock, hEvent, &events);
/* イベント変数をリセット*/
WSAResetEvent(hEvent);
/* 発生したイベントがREADであればデータを読み込む*/
if(events.lNetworkEvents & FD_READ){
iRcvLen=recv(AcceptSock, caRcvDat, 1024, 0);
/* ・・・以下Recv後の動作・・・*/
}
}
おそらく、2回目のWSAWaitForMultipleEvents関数で待機している間に接続要求が来たクライアントを取りこぼしているのだと思いますが、
対処方法がわかりません。
お礼
ノンブロッキングにした場合データが受信途中のまま次の処理に移行してしまうということになるんですね。 H/W特性やデータ内容を考えた時にはブロッキングの方が良くなることもあるということを考えながらこれからプログラムを作っていきたいと思います。 ありがとうございました。