Failed IOCP attempt

Started by
1 comment, last by Len Holgate 11 years, 12 months ago
Hello,

I've been reading through posts and noticed some people suggest to use IOCP on server to handle a lot packets more efficiently. I've used http://askldjd.wordp...r-1-2-released/ as some kind of reference and tried to initialize basic IOCP and get it it working, however I get WSA_INVALID_PARAMETER error in GetQueuedCompletionStatus inside worker thread when client attempts to connect.

Here's my code:

void main() {
WSADATA wsaData;
int numThreads = 1;
vector<HANDLE> threads;

// InitializeWinsock();
WSAStartup(MAKEWORD(2,2), &wsaData);

// InitializeIocp();
m_ioCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, numThreads);
if(m_ioCompletionPort == NULL)
cout << "CreateIoCompletionPort() => " << WSAGetLastError() << endl;

// InitializeThreadPool();
threads.reserve(numThreads);
for(auto i = 0; i < numThreads; ++i)
threads.push_back(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&WorkerThread, m_ioCompletionPort, 0, 0));

// InitializeSocket();
InitializeSocket(ADDR_ANY, 50000);

// InitializeAcceptEvent();
m_socket = CreateOverlappedSocket();
PostAccept();

// client (?)
SOCKET client = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
sockaddr_in address = { };
address.sin_family = AF_INET;
address.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
address.sin_port = htons(50000);
auto result = WSAConnect(client, (sockaddr*)&address, sizeof(address), 0, 0, 0, 0);
if(result == SOCKET_ERROR)
cout << "WSAConnect() => " << WSAGetLastError() << endl;

system("pause");
}

void WorkerThread(HANDLE m_ioCompletionPort) {
for(;;) {
void *key = nullptr;
OVERLAPPED *overlapped = nullptr;
DWORD bytesTransferred = 0;

BOOL completionStatus = GetQueuedCompletionStatus(m_ioCompletionPort, &bytesTransferred, (LPDWORD)&key, &overlapped, INFINITE);

if(completionStatus == FALSE) {
cout << "GetQueuedCompletionStatus() => " << WSAGetLastError() << endl;
continue;
}

if(key == NULL) {
cout << "GetQueuedCompletionStatus() => " << WSAGetLastError() << endl;
break;
}
}
}

SOCKET CreateOverlappedSocket() {
return WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
}

LPFN_ACCEPTEX LoadAcceptEx(SOCKET s) {
LPFN_ACCEPTEX lpfnAcceptEx = NULL;
DWORD dwBytes = 0;
GUID GuidAcceptEx = WSAID_ACCEPTEX;

auto result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &dwBytes, NULL, NULL);
if(result == SOCKET_ERROR) {
cout << "WSAIoctl() => " << WSAGetLastError() << endl;
return nullptr;
}

return lpfnAcceptEx;
}

void AssociateDevice(HANDLE h) {
auto result = CreateIoCompletionPort(h, m_ioCompletionPort, 0, 0);
if(result == NULL) {
cout << "CreateIoCompletionPort() => " << WSAGetLastError() << endl;
return;
}
}

void InitializeSocket(uint32 addressToListenOn, uint16 portNumber) {
m_listenSocket = CreateOverlappedSocket();

sockaddr_in serverAddress = { };
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = addressToListenOn;
serverAddress.sin_port = htons(portNumber);

auto result = bind(m_listenSocket, (sockaddr*)&serverAddress, sizeof(serverAddress));
if(result == -1) {
cout << "bind() => " << WSAGetLastError() << endl;
return;
}

result = listen(m_listenSocket, SOMAXCONN);
if(result == SOCKET_ERROR) {
cout << "listen() => " << WSAGetLastError() << endl;
return;
}

m_acceptExFn = LoadAcceptEx(m_listenSocket);
if(m_acceptExFn == FALSE) {
cout << "LoadAcceptEx() => " << WSAGetLastError() << endl;
return;
}

AssociateDevice((HANDLE)m_listenSocket);
}

void PostAccept() {
DWORD bytesReceived_ = 0;
DWORD addressSize = sizeof(sockaddr_in) + 16;
auto result = m_acceptExFn(m_listenSocket, m_socket, m_data, 0, addressSize, addressSize, &bytesReceived_, 0/*&m_acceptContext*/);
if(result == 0) {
if(WSAGetLastError() != WSA_IO_PENDING)
cout << "m_acceptExFn() => " << WSAGetLastError() << endl;
return;
}

result = PostQueuedCompletionStatus(m_ioCompletionPort, 0, 0, 0/*&m_acceptContext*/);
if(result == 0) {
cout << "PostQueuedCompletionStatus() => " << WSAGetLastError() << endl;
return;
}
}
Advertisement
AcceptEx() requires that you specify an LPOVERLAPPED for the final parameter. The documentation explicitly states that it cannot be NULL.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

If you want to get up to speed on IOCP in general you might find my free IOCP client/server code of some use, it's pretty old now but it works well and the articles that I wrote for CodeProject explain what's going on.

You can download the code from here and there are links to the articles that explain it.

This topic is closed to new replies.

Advertisement