#sockets #io-completion-ports
#сокеты #завершение ввода-вывода-порты
Вопрос:
Я пишу серверное приложение и хочу использовать порты IOCompletion, поэтому я написал прототип для сервера, но я столкнулся с проблемой GetQueuedCompletionStatus, которую он никогда не возвращает (блокирует). Ниже приведен мой код:
bool CreateSocketOverlappedServer()
{
WSADATA wsaData;
SOCKADDR_IN sockaddr;
if(WSAStartup(MAKEWORD(2,2,),amp;wsaData)){
_tprintf(_T("Unable to start upn"));
return false;
}
SrvSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);
if(SrvSocket==INVALID_SOCKET){
_tprintf(_T("Unable to start socketn"));
return false;
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(10000);
sockaddr.sin_addr.s_addr = INADDR_ANY;
/* now bind the socket */
if(bind(SrvSocket, (SOCKADDR *)amp;sockaddr, sizeof(SOCKADDR_IN))==SOCKET_ERROR){
_tprintf(_T("Unable to bind socketn"));
return false;
}
if(listen(SrvSocket, 5)==SOCKET_ERROR){
_tprintf(_T("Error listeningn"));
return false;
}
return true;
}
void WorkerThread(void *arg)
{
bool bret= false;
DWORD dwTransferedBytes=0;
CLIENTS *client;
PPER_IO_OPERATION_DATA data;
/* Just sleep for now */
while(true){
_tprintf(_T("Entering whilen"));
bret = GetQueuedCompletionStatus(hIocp,amp;dwTransferedBytes,(PULONG_PTR)amp;client,(LPOVERLAPPED *) amp;data,INFINITE);
if(!bret){
_tprintf(_T("Unable to process completion portn"));
}
}
//Sleep(10000);
}
void AcceptClientConnections(void *arg)
{
SOCKET ClientSocket;
CLIENTS *c;
_tprintf(_T("Start accepting client connectionsn"));
while(true){
ClientSocket = accept(SrvSocket, NULL,NULL);
if(ClientSocket==INVALID_SOCKET){
_tprintf(_T("Unable to accept connectionn"));
continue;
}
/* do an association with completion port */
c = (CLIENTS *)malloc(sizeof(CLIENTS));
c->sock = ClientSocket;
/* associate with completion port */
if(!CreateIoCompletionPort((HANDLE)ClientSocket, hIocp, (ULONG_PTR)c,0)){
_tprintf(_T("Unable to associate with completion portn: %d"),GetLastError());
}
}
}
Есть идеи?
заранее спасибо.
Ответ №1:
Вы неправильно используете порт завершения, поэтому ему нечего делать, и, следовательно, нет статуса для отчета. Использование порта завершения с сокетами - это двухэтапный процесс, но вы выполняете только половину шагов.
Прочитайте следующую статью MSDN для получения подробной информации:
Сокеты Windows 2.0: запись масштабируемых приложений Winsock с использованием портов завершения
Комментарии:
1. Возможно, вы также захотите взглянуть на мою бесплатную клиент-серверную платформу IOCP, которая показывает несколько более продвинутое использование IOCP, чем образец MSDN, и, надеюсь, ее немного легче повторно использовать в вашем прототипе: serverframework.com/products---the-free-framework.html
2. Реми, пожалуйста, поясни это, я создаю порт Iocompletion, например: hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,0,0,), затем связываю каждый принятый сокет с этим портом завершения, в моем пуле потоков вызывается GetQueuedCompletionStatus, но я сталкиваюсь с тем, что он никогда не возвращается, я имею в видуон блокируется навсегда, я подключаюсь к серверу через telnet и отправляю любую строку, но GetQueuedCompletionStatus блокирует. есть предложения?
3. Вы не показали начальный
CreateIoCompletionPort()
вызов в опубликованном вами коде и не показали никакого кода, который использует сокеты после их подключения. Например, вы вызываетеWSARecv()
соWSAOVERLAPPED
структурой, чтобы начать чтение из принятого сокета через перекрывающийся ввод-вывод? Вам нужно это сделать, чтобы инициироватьGetQueuedCompletionStatus()
входящие данные.4. Извините, потому что я не показываю вызов CreateIoCompletionPort, но вызов WSARecv выполняется после GetQueuedCompletionStatus, верно?
5. Нет, вы должны вызвать
WSARecv()
afteraccept()
возвращает новый дескриптор сокета для клиента.GetQueuedCompletionStatus()
невозможно сообщить о состоянии для чего-то, что еще не было поставлено в очередь. Вы ставите в очередь перекрывающееся чтение сWSARecv()
, затемGetQueuedCompletionStatus()
сообщает, когда чтение фактически получает некоторые данные от клиента, затем вы отправляете другоеWSARecv()
в очередь другой операции чтения и так далее. То же самое с отправкой данных. Ставьте в очередь операцию отправки сWSASend()
помощью, затемGetQueuedCompletionStatus()
сообщает, когда отправка завершена.
Ответ №2:
Одна из возможностей: проверьте, связали ли вы сокет прослушивателя с портом завершения (сам допустил эту ошибку). Если вы этого не сделаете, функция GetQueuedCompletionStatus() заблокирует навсегда.