2015-10-08 141 views
-1

基本上,就是這樣。同時,客戶的連接呼叫是成功的。這怎麼可能?我沒有添加任何代碼,因爲我不知道錯誤在哪裏。FD_ACCEPT檢測到,但然後調用'接受'失敗,10038 - WSAENOTSOCK

服務器:檢測FD_ACCEPT。呼叫接受()失敗。

客戶端:呼叫連接()成功。然後它檢測到FD_CONNECT。以下send()成功。之後的send()失敗(10053 - WSAECONNABORTED)。

void Server::get_addressinfo() { 
    // Resolve the local address and port to be used by the server 
    const char * p = port.c_str(); 
    int iResult = getaddrinfo(NULL, p, &hints, &result); 
    if (iResult != 0) { 
     throw MyException("getaddrinfo failed."); 
    } 
} 

void Server::create_socket() { 
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
    if (ListenSocket == INVALID_SOCKET) { 
     throw MyException("socket creation failed."); 
    } 
} 

void Server::bind_socket() { 
    int iResult = bind(ListenSocket, result->ai_addr, (int) result->ai_addrlen); 
    if (iResult == SOCKET_ERROR) { 
     closesocket(ListenSocket); 
     throw MyException("bind failed."); 
    } 
} 

void Server::listen_for_connection() { 
    int iResult = listen(ListenSocket, SOMAXCONN); 
    if (iResult == SOCKET_ERROR) { 
     closesocket(ListenSocket); 
     throw MyException("listen failed."); 
    } 
} 

void Server::goLive() { 
    get_addressinfo(); 
    create_socket(); 
    bind_socket(); 
    listen_for_connection(); 
    wait_for(FD_ACCEPT); 
    accept_connection(); 
} 

void Server::wait_for(u_int event_type) { 
    WSAEVENT event = WSACreateEvent(); 
    WSAEventSelect(ListenSocket, event, event_type); 
    WSAEVENT lphEvents[1] = {event}; 
    WSANETWORKEVENTS NetworkEvents = {0}; 
    int nReturnCode = WSAWaitForMultipleEvents(1, &lphEvents[0], false, WSA_INFINITE, false); 
    if (nReturnCode==WSA_WAIT_FAILED) 
     throw MyException("WSA__WAIT_FAILED.\n"); 
    if (WSAEnumNetworkEvents(ListenSocket, lphEvents[0], &NetworkEvents) == SOCKET_ERROR) 
     throw MyException("WSAEnumNetworkEvents => SOCKET_ERROR.\n"); 
    WSACloseEvent(event); ***// THIS WAS THE BUG !!!*** 
} 

void Server::accept_connection() { 
    ClientSocket = accept(ListenSocket, NULL, NULL); 
    if (ClientSocket == INVALID_SOCKET) { 
     closesocket(ListenSocket); 
     throw MyException("accept failed."); 
    } 
} 
+1

錯誤信息幾乎不可能更清晰,'錯誤在哪裏'顯然是在調用'accept()'。但如果你不想要答案,不要發佈代碼。隨你便。 – EJP

+0

添加了代碼。 – Earnie

+1

如果接受失敗,爲什麼要關閉偵聽套接字?這是否應該只接受一個連接或者是處理多個連接的方案的一部分? –

回答

0

我在代碼上做了一些改進,但是bug仍然存在。現在我發現了問題行:

WSACloseEvent(event); 

註釋掉後,服務器接受連接。

從MSDN WSACloseEvent函數文檔:

的WSACloseEvent功能關閉句柄到一個事件對象並釋放與該事件對象相關聯的資源。

我想這意味着它釋放了socket =>因此10038 - WSAENOTSOCK。我落入了與INVALID_SOCKET不相等的套接字值。所以我認爲套接字是有效的。它不是......

+0

你應該刪除整個事件的事情。你不需要它。 accept()方法已經被阻塞。如果您需要計時,請使用SO_RCVTIMEO。 – EJP

+0

我可以重現錯誤。這很奇怪,因爲'WSACreateEvent()'簡單地調用'CreateEvent()','WSAWaitForMultipleEvents()'簡單地調用'WaitForMultipleObjectsEx()',而'WSACloseEvent()'簡單地調用'CloseHandle()'。所以你實際上關閉了一個標準的Win32事件,這與套接字無關。另一方面,我猜'WSAEventSelect()'是以某種方式將它們連接在一起的,所以關閉一個關閉另一個。 –

+0

@EJP:或者,你可以在調用accept()之前使用'select()'。 –

相關問題