I am trying to code a small test-server for completion ports. But when I try to call Accept开发者_如何学GoEx... it always returns WSAEINVAL as the winsock error code... I don´t really get what was my mistake
http://codepad.org/NEXG3Ssh <- code on codepad
and
StartWinsock();
cout << "Winsock initiated\n";
//Get the number of processors
DWORD ulProcessors = GetNumberOfProcessors();
cout << "Number of Processors/Threads, that will be used: " << ulProcessors << endl;
//Create an completion port
hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, ulProcessors);
if(hCompletionPort == NULL)
ErrorAbort("Could not create completion port");
cout << "Completion Port created\n";
//Create threads
CreateThreads(ulProcessors);
cout << "Threads created\n";
//Create socket
AcceptorSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addrinfo *final, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_flags = AI_PASSIVE;
if(getaddrinfo(NULL,"12345", &hints, &final))
ErrorAbort("Could not retrieve address information");
if(bind(AcceptorSock,final->ai_addr, final->ai_addrlen))
ErrorAbort("Could not bind socket");
freeaddrinfo(final);
cout << "Acceptor socket created and bound\nStarting to listen on the acceptor socket\n";
if(listen(AcceptorSock, 2))
ErrorAbort("Can´t listen on the socket");
//Add acceptor socket file handle to be observed by the completion port
if(CreateIoCompletionPort((HANDLE)AcceptorSock, hCompletionPort, NEW_CONNECTION, 0) != hCompletionPort)
ErrorAbort("A new completion port has been created instead of using the existing one");
cout << "Acceptor socket associated with the completion port\n";
ResumeThreads(2);
char lpOutputBuf[1024];
int outBufLen = 1024;
DWORD dwBytes;
OVERLAPPED over;
SOCKET newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
while(true)
{
memset(&over, 0, sizeof(over));
if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
{
int x = WSAGetLastError();
if( x != WSA_IO_PENDING)
ErrorAbort("Could not acceptex a new connection");
}
}
Te problem in your code is this:
while(true)
{
memset(&over, 0, sizeof(over));
if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
{
int x = WSAGetLastError();
if( x != WSA_IO_PENDING)
ErrorAbort("Could not acceptex a new connection");
}
}
The second parameter of the AcceptEx Function (in this case newSock) must be a unconnected and unbound socket, then when a new connection arrives the newSock parameter will be an invalid parameter (because now is connected), to avoid this a New Socket Handle must be created, but the loop must wait until the new connection arrives, to do this a WSAEVENT must be use. The first the function WSAEventSelect must be used to associate the FD_ACCEPT Network event with the WSAEVENT, this mus be done before the creation of the AcceptThread:
g_ev = WSACreateEvent();
if (WSA_INVALID_EVENT == g_ev)
ErrorAbort("Error occurred while WSACreateEvent()";
if (SOCKET_ERROR == WSAEventSelect(AcceptorSock, g_ev, FD_ACCEPT))
{
WSACloseEvent(g_ev);
ErrorAbort("Error occurred while WSAEventSelect().");
}
The AcceptThread Then Call The AcceptEx Function and Wait for a New Connection, when a new connection arrives the newSock is Added to the Completion port and a new Socket is created, this thread have only the elements required to accept connections:
DWORD WINAPI AcceptThread(LPVOID lParam)
{
SOCKET AcceptorSock = (SOCKET)lParam, new;
SOCKET newSock;
OVERLAPPED over;
DWORD wr;
memset(&over, 0, sizeof(over));
do
{
newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
{
int x = WSAGetLastError();
if (x != ERROR_IO_PENDING)
{
cout << "Could not acceptex a new connection" << endl;
return 1;
}
else
{
if (WSA_WAIT_TIMEOUT != (wr = WSAWaitForMultipleEvents(1, &g_ev, FALSE, INFINITE, FALSE)))
{
WSAEnumNetworkEvents(AcceptorSock, g_ev, &WSAEvents);
if ((WSAEvents.lNetworkEvents & FD_ACCEPT) && (0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT]))
{
if (CreateIoCompletionPort(newSock, hCompletionPort, 0, 0) == NULL)
{
cout << "Error CreateIoCompletionPort" << endl;
return 2;
}
WSAResetEvent(g_ev);
}
}
}
}
}while(wr != WSA_WAIT_EVENT_0);
}
If any body needs more information this links could be useful: http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedscalableapp6b.html http://www.codeproject.com/KB/IP/SimpleIOCPApp.aspx http://msdn.microsoft.com/en-us/magazine/cc302334.aspx
SOCKET newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
should use WSASocket
rather than socket
and you should pass the WSA_FLAG_OVERLAPPED
flag when creating the socket.
精彩评论