我正在尝试为完成端口编写一个小型测试服务器。 但是当我尝试调用AcceptEx时...它总是返回WSAEINVAL作为winsock错误代码... 我真的不明白我的错误
http://codepad.org/NEXG3Ssh< - 代码板上的代码
和
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");
}
}
答案 0 :(得分:2)
代码中的问题是:
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");
}
}
AcceptEx函数的第二个参数(在本例中为newSock)必须是未连接和未绑定的套接字,然后当新连接到达时,newSock参数将是一个无效参数(因为现在已连接),以避免这个必须创建套接字句柄,但循环必须等到新连接到达,为此必须使用WSAEVENT。第一个函数WSAEventSelect必须用于将FD_ACCEPT网络事件与WSAEVENT关联,这可以在创建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().");
}
AcceptThread然后调用AcceptEx函数并等待新连接,当新连接到达时,newSock被添加到Completion端口并创建一个新的Socket,该线程只有接受连接所需的元素:
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);
}
如果任何机构需要更多信息,此链接可能有用: http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedscalableapp6b.html http://www.codeproject.com/KB/IP/SimpleIOCPApp.aspx http://msdn.microsoft.com/en-us/magazine/cc302334.aspx
答案 1 :(得分:-1)
SOCKET newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
应该使用WSASocket
而不是socket
,并且在创建套接字时应该传递WSA_FLAG_OVERLAPPED
标志。