私はTCPサーバーを書いています(ソケットモデルをブロックしています)。サーバーがAcceptでの新しい接続試行を待機(ブロック)しているときに、有効な通常のプログラム終了を実装するのに問題があります(私はWSAcceptを使用しています)。サーバーのリッスン ソケットのコードは次のようなものです (エラー処理やその他の無関係なコードは省略しました)。
int ErrCode = WSAStartup(MAKEWORD(2,2), &m_wsaData) ;
// Create a new socket to listen and accept new connection attempts
struct addrinfo hints, *res = NULL, *ptr = NULL ;
int rc, count = 0 ;
memset(&hints, 0, sizeof(hints)) ;
hints.ai_family = AF_UNSPEC ;
hints.ai_socktype = SOCK_STREAM ;
hints.ai_protocol = IPPROTO_TCP ;
hints.ai_flags = AI_PASSIVE ;
CString strPort ;
strPort.Format("%d", Port) ;
getaddrinfo(pLocalIp, strPort.GetBuffer(), &hints, &res) ;
strPort.ReleaseBuffer() ;
ptr = res ;
if ((m_Socket = WSASocket(res->ai_family, res->ai_socktype, res->ai_protocol, NULL, 0, 0)) == INVALID_SOCKET)
{
// some error
}
if(bind(m_Socket, (SOCKADDR *)res->ai_addr, res->ai_addrlen) == SOCKET_ERROR)
{
// some error
}
if (listen(m_Socket, SOMAXCONN) == SOCKET_ERROR)
{
// some error
}
ここまでは順調です...次に、次のようにスレッド内に WSAccept 呼び出しを実装しました。
SOCKADDR_IN ClientAddr ;
int ClientAddrLen = sizeof(ClientAddr) ;
SOCKET TempS = WSAAccept(m_Socket, (SOCKADDR*) &ClientAddr, &ClientAddrLen, NULL, NULL);
もちろん、新しい接続試行が行われるまで WSAccept はブロックされますが、プログラムを終了したい場合は、WSAccept を終了させる何らかの方法が必要です。私はいくつかの異なるアプローチを試しました:
- 別のスレッド内から m_Socket を使用して shutdown および/または closesocket を呼び出そうとすると失敗しました (プログラムがハングするだけです)。
- 実際、WSAEventSelect を使用するとこの問題は解決しますが、WSAccept はノンブロッキング ソケットのみを配信します。これは私の意図ではありません。(ソケットをブロックする方法はありますか?)
- APC について読んで、 QueueUserAPC(MyAPCProc, m_hThread, 1)) のようなものを使用しようとしましたが、どちらも機能しませんでした。
私は何を間違っていますか?このブロッキング WSAccept を終了させるより良い方法はありますか?