c++ - AcceptEx 返回 1022 (WSAEINVAL)...我做错了什么?

标签 c++ winsock overlapped-io

我正在尝试为完成端口编写一个小型测试服务器。 但是当我尝试调用 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");
  }
 }

最佳答案

您的代码中的问题是这样的:

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)必须是一个未连接和未绑定(bind)的套接字,那么当一个新的连接到达时newSock参数将是一个无效参数(因为现在已经连接),以避免这个New必须创建套接字句柄,但循环必须等到新连接到达,为此必须使用 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

关于c++ - AcceptEx 返回 1022 (WSAEINVAL)...我做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4341372/

相关文章:

C++。 Child 继承自 Parent 并作为 Parent 属性包含在内

c++ - Winsock C++ 连接超时

select - 确定用winsock(FIONWRITE)可以发送多少字节?

c++ - 在 Windows 上使用重叠命名管道进行同时读写

c++ - 我应该使用 AcceptEx() 还是 WSAAccept()?

C++串口库对Win32同步函数的使用?

c++ - 如何比系统更喜欢 AddFontMemResourceEx 加载的字体?

c++ - 让 boost 程序选项在函数作用域后持续存在

windows-8 - VB6应用程序通过winsock发送UDP广播消息 - 仅每隔一条消息发送一次

c++ - 在容器之间传输数据时如何解决可能丢失数据的警告?