إرجاع قبول 1022 (wsaeinval) ... ماذا فعلت خطأ؟
-
30-09-2019 - |
سؤال
أحاول ترميز خادم اختبار صغير لمنافذ الانتهاء. لكن عندما أحاول الاتصال بـ 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
العلم عند إنشاء المقبس.