Я пытаюсь написать сервер UDP с рабочим потоком, который продолжает вызывать GetQueuedCompletionStatus
.Я уже могу успешно получать данные с помощью WSARecvFrom
, но отправка данных с помощью WSASendTo
вызывает следующую ошибку:
10045: The attempted operation is not supported for the type of object referenced.
Я пытался исправить это в течение нескольких часов, читаядокументация, а также строгий метод проб и ошибок.Переключение вызова WSASendTo
на блокирующий вызов устраняет проблему, но затем мне приходится иметь дело с блокировкой ввода-вывода.У меня также есть почти такой же код для TCP (WSASend
вместо WSASendTo
и т. Д.), И он работает с IOCP без помех.
Я пытался вызвать connect
, без привязкисокет, изменив структуру OVERLAPPED
, проверил, что параметр SOCKADDR*
содержит допустимую комбинацию хост / порт, передав параметр lpNumberOfBytesSent
.Ничто, похоже, не имеет значения.
Базовый ход программы (код ниже):
- Создайте сокет с
WSA_FLAG_OVERLAPPED
- Создать порт завершения ввода-вывода и рабочий поток
- Привязать сокет к 127.0.0.1:2050
- Вызвать
WSARecvFrom
(и соединиться с другим клиентом для установки действительного PER_IO_DATA::SockAddrFrom
) gets_s
введите с консоли и отправьте его с WSASendTo
Моя структура OVERLAPPED:
typedef struct PER_IO_DATA
{
OVERLAPPED Overlapped;
SOCKET Socket;
WSABUF wsaBuf;
char Buffer[1024];
DWORD Flags;
SOCKADDR_IN SockAddrFrom;
} PER_IO_DATA;
Основная функция:
//################################# Initialize ###############################
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
return 0;
//Create completion port
HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (!hCompletionPort)
return 0;
//Create and detach a worker thread
HANDLE hThread = CreateThread(NULL, 0, server_worker_thread, hCompletionPort, 0, NULL);
CloseHandle(hThread);
//Create UDP socket with overlapped IO
SOCKET Sock = WSASocketW(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (Sock == INVALID_SOCKET)
WSAERROR();
//################################### Bind ###################################
//Bind socket to 127.0.0.1:2050
SOCKADDR_IN serverAddr = { 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(2050);
InetPtonA(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);
if (bind(Sock, (SOCKADDR*)&serverAddr, sizeof(SOCKADDR_IN)) == -1)
WSAERROR();
//Assign completion port
CreateIoCompletionPort((HANDLE)Sock, hCompletionPort, 0, 0);
//Create overlapped context
PER_IO_DATA* pPerIoData = malloc(sizeof(PER_IO_DATA));
ZeroMemory(pPerIoData, sizeof(PER_IO_DATA));
pPerIoData->Socket = Sock;
pPerIoData->Overlapped.hEvent = WSACreateEvent();
pPerIoData->wsaBuf.buf = pPerIoData->Buffer;
pPerIoData->wsaBuf.len = sizeof(pPerIoData->Buffer);
//################################## Receive #################################
int size = sizeof(SOCKADDR_IN);
if (WSARecvFrom(Sock, &pPerIoData->wsaBuf, 1, NULL,
&pPerIoData->Flags, (SOCKADDR*)&pPerIoData->SockAddrFrom,
&size, &pPerIoData->Overlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
WSAERROR();
}
//################################### Send ###################################
while (TRUE)
{
gets_s(pPerIoData->Buffer, sizeof(pPerIoData->Buffer));
pPerIoData->wsaBuf.len = strlen(pPerIoData->Buffer);
//Print outgoing data
char addr[16];
DEBUG("Sending %.*s (%d bytes) to %s:%d", pPerIoData->wsaBuf.len, pPerIoData->Buffer,
pPerIoData->wsaBuf.len, InetNtopA(AF_INET, &pPerIoData->SockAddrFrom.sin_addr,
addr, sizeof(addr)), ntohs(pPerIoData->SockAddrFrom.sin_port));
//Send the data (this is where the error happens)
if (WSASendTo(Sock, &pPerIoData->wsaBuf, 1, NULL,
WSA_FLAG_OVERLAPPED, (SOCKADDR*)&pPerIoData->SockAddrFrom, sizeof(SOCKADDR_IN),
&pPerIoData->Overlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
WSAERROR(); //<-- Error 10045
}
}
//################################## Clean up ################################
shutdown(Sock, SD_BOTH);
closesocket(Sock);
WSACleanup();
return 0;
Пример вывода:
Received hello (5 bytes) from 127.0.0.1:50995
respond
Sending respond (7 bytes) to 127.0.0.1:50995
Error 10045: The attempted operation is not supported for the type of object referenced.
Сообщение об ошибке исходит из моего WSAERROR
макроса.
Как мне позвонить WSASendTo
с WSA_FLAG_OVERLAPPED
и добавить его в очередь сообщений IOCP?