「特別な」アドレスを使用しようとする代わりに、while
ループが参照できるアプリのメモリ内のどこかにフラグを設定しconnect()
てから、サーバー マシンのローカル IP のいずれかにバインドされている通常のソケットを設定します (connect()
バインディングを処理します)。 、bind()
手動で呼び出す必要はありません)、例:
bool shutting_down = false;
.
while (!shutting_down)
{
auto new_connected_socket = accept(listening_socket,...);
// Here it may block for a long time
if (shutting_down)
{
closesocket(new_connected_socket);
break;
}
std::thread(fn_new_connection_handler, new_connected_socket);
}
.
shutting_down = true;
if (server is listening)
{
sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(my server port);
server_addr.sin_addr.s_ddr = inet_addr("127.0.0.1");
SOCKET wakeup_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(wakeup_socket, (sockaddr*)&server_addr, sizeof(server_addr));
closesocket(wakeup_socket);
}
より良いアプローチは、単純にリスニング ソケットを非ブロッキング モードにselect()
し、ループ内でタイムアウトを使用して、定期的に起動できるようにすることです。
while (!shutting_down)
{
fd_set rds;
FD_ZERO(&rds);
FD_SET(listening_socket, &rds);
timeval t;
t.tv_sec = 5;
t.tv_usec = 0;
if ((select(0, &rds, NULL, NULL, &t) > 0) && (!shutting_down))
{
auto new_connected_socket = accept(listening_socket,...);
std::thread(fn_new_connection_handler, new_connected_socket);
}
}
さらに良いことに、の代わりにWSACreateEvent()
andを使用します。WSAWaitForMultipleEvents()
select()
WSAEVENT hShutdownEvent = WSACreateEvent();
.
WSAEVENT hAcceptEvent = WSACreateEvent();
WSAEventSelect(listening_socket, hAcceptEvent, FD_ACCEPT);
while (true)
{
WSAEVENT hEvents[2];
hEvents[0] = hAcceptEvent;
hEvents[1] = hShutdownEvent;
DWORD dwRet = WSAWaitForMultipleEvents(2, hEvents, FALSE, INFINITE, FALSE);
if (dwRet == WSA_WAIT_EVENT_0)
{
auto new_connected_socket = accept(listening_socket,...);
std::thread(fn_new_connection_handler, new_connected_socket);
}
else
break;
}
WSACloseEvent(hAcceptEvent);
.
if (server is listening)
WSASetEvent(hShutdownEvent);