#c #multithreading #sockets #winapi
#c #многопоточность #сокеты #winapi
Вопрос:
У меня есть основная программа, которая генерирует несколько потоков (используя цикл while с accept() для получения клиентов), и все, что ей нужно сделать, это «слушать клавиатуру», и когда пользователь вводит слово exit, оно закрывает всю программу. сначала основная программа создает поток прослушивания, затем он входит в цикл while, который принимает клиентов. даже если слушающий поток получает ввод exit, цикл все еще застревает на accept.
мне не нужно использовать отдельный поток для прослушивания клавиатуры, но я не смог найти способ блокировки, который бы работал.
прослушивающий поток:
DWORD WINAPI ListenService(LPVOID lpParam)
{
char buffer[5];
if (EOF == scanf("%s", buffer))
{
printf("faile get word from keyboardn");
}
if (buffer[4] != '')
strcat(buffer, "");
if (STRINGS_ARE_EQUAL(buffer, "exit"))
{
return 999;
}
return -1;
}
в основном коде:
ThreadListen = CreateThread(NULL,0,ListenService,NULL,0,amp;(ThreadId));
while(1)
{
SOCKET AcceptSocket = accept(MainSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET)
{
printf("Accepting connection with client failed, error %ldn", WSAGetLastError());
CleanupWorkerThreads();
WSACleanup();
}
printf("Client Connected.n");
}
Комментарии:
1. Не связано, но в документации CreateThread говорится следующее: «Поток в исполняемом файле, который вызывает библиотеку времени выполнения C (CRT), должен использовать функции
_beginthreadex
and_endthreadex
для управления потоками, а неCreateThread
andExitThread
» .2. Вызовите ExitProcess() .
Ответ №1:
Есть много разных способов справиться с этим.
Вы можете прервать блокировку accept()
, просто закрыв прослушивающий сокет.
Или вы можете использовать select()
с коротким таймаутом, чтобы определить, когда новый клиент ожидает перед вызовом accept()
. Вы можете проверить свое условие выхода между вызовами select()
. Просто имейте в виду, что существует небольшое условие гонки, при котором клиент может отключиться между временем select()
и accect()
вызовом, поэтому все равно accept()
может блокироваться, если больше нет ожидающих клиентов.
Или вы можете избавиться от своих потоков и просто использовать неблокирующие сокеты в одном потоке, периодически проверяя условие выхода между операциями сокета.
Или вы можете использовать асинхронные сокеты, используя WSACreateEvent()
, WSAEventSelect()
, и WSAWaitForMultipleEvents()
для обнаружения активности сокета. Затем вы можете создать событие добавления для ожидания, когда произойдет условие выхода.
Или вы можете использовать порт завершения ввода-вывода для обработки активности сокета, а затем вы можете отправить пользовательский пакет выхода в очередь IOCP, используя PostQueuedCompletionStatus()
для «пробуждения» любых ожидающих потоков.
Комментарии:
1. я думаю, что опция выбора может быть решением, которое я ищу, я попытался прочитать select в Windows doc, но смог найти способ использовать его для обнаружения нового клиента, которого я жду, и, возможно, вы можете подробнее рассказать об этой опции?
2. @dinohayon прослушивающий сокет находится в состоянии чтения, когда у него есть клиент, ожидающий принятия. Так что просто вызывайте
select()
запрос для удобства чтения, используя anfd_set
, содержащий прослушивающий сокет. Если прослушивающий сокет доступен для чтения,FD_ISSET()
он сообщит true для этого сокетаfd_set
послеselect()
выхода.