سؤال

أحاول ترميز خادم اختبار صغير لمنافذ الانتهاء. لكن عندما أحاول الاتصال بـ AceptEx ... فإنه يعيد دائمًا wsaeinval كرمز خطأ Winsock ... لا أحصل حقًا على ما كان خطأي

http://codepad.org/nexg3ssh <- رمز على codepad

و

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 في الكود الخاص بك هي:

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");
  }
}

يجب أن تكون المعلمة الثانية لوظيفة القبول (في هذه الحالة Newsock) مقبسًا غير مرتبط وغير محدود ، ثم عندما يصل اتصال جديد ، ستكون معلمة Newsock معلمة غير صالحة (لأن الآن متصل) ، لتجنب هذا المقبس الجديد يتم إنشاؤها ، ولكن يجب أن تنتظر الحلقة حتى يصل الاتصال الجديد ، للقيام بذلك ، يجب استخدام WSAEVENT. أول وظيفة يجب استخدام الوظيفة wsaeventselect لربط حدث شبكة FD_ACCEPT مع WSAEVENT ، يتم إجراء هذا قبل إنشاء القبول:

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().");
}

ثم استدعاء قبول وظيفة القبول وانتظر اتصالًا جديدًا ، عند وصول اتصال جديد ، تتم إضافة Newsock إلى منفذ الانتهاء ويتم إنشاء مأخذ توصيل جديد ، هذا الموضوع له فقط العناصر المطلوبة لقبول الاتصالات:

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/winsock2advancedscalablePapp6b.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);

يجب استخدام WSASocket عوضا عن socket ويجب أن تمرر WSA_FLAG_OVERLAPPED العلم عند إنشاء المقبس.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top