2013-02-04 35 views
0

我正在編寫用於處理基本操作(如連接,發送和接收數據)的UDP套接字類的C++代碼。我嘗試使用WSAEventSelect的網絡事件機制來處理與套接字相關的基本操作。 當我使用WSASend將數據發送到接收數據的(UDP)目的地時,一切都很順利。 但是,當我使用WSASend將數據發送到不存在的目標(UDP)或無法通過網絡訪問時,我會觸發FD_READ事件。這當然會導致嚴重的問題,因爲沒有實際的數據可以接收!WSASend for UDP套接字觸發器FD_READ當沒有可用的目標時

我無法解釋爲什麼會發生這種情況 - 有什麼想法?
也許我做錯了什麼,這裏是我的代碼相關部分:

WSADATA m_wsaData ;   
SOCKET m_Socket ;   
WSAEVENT m_SocketEvent ; 

if(WSAStartup(MAKEWORD(2,2), &m_wsaData) != 0) 
{ 
// some error 
} 

// Create a new socket to receive datagrams on 
struct addrinfo hints, *res = NULL ; 
int rc ; 
memset(&hints, 0, sizeof(hints)) ; 
hints.ai_family = AF_UNSPEC ; 
hints.ai_socktype = SOCK_DGRAM ; 
hints.ai_protocol = IPPROTO_UDP ; 

rc = getaddrinfo("SomePC", "3030", &hints, &res) ; 

if(rc == WSANO_DATA) 
{ 
    // some error 
} 

if ((m_Socket = WSASocket(res->ai_family, res->ai_socktype, res->ai_protocol, NULL, 0, 0)) == INVALID_SOCKET) 
{ 
    // some error 
} 

// create event and associate it with the socket 
m_SocketEvent = WSACreateEvent() ; 
if(m_SocketEvent == WSA_INVALID_EVENT) 
{ 
    // some error 
} 
// associate only the following events: close, read, write 
if(SOCKET_ERROR == WSAEventSelect(m_Socket, m_SocketEvent, FD_CLOSE+FD_READ+FD_WRITE)) 
{ 
    // some error 
} 

// connect to a server 
int ConnectRet = WSAConnect(m_Socket, (SOCKADDR*)res->ai_addr, res->ai_addrlen, NULL, NULL, NULL, NULL) ; 
if(ConnectRet == SOCKET_ERROR) 
{ 
    // some error 
} 

然後,每當我嘗試通過套接字發送一些數據沒有被監聽或(UDP套接字)目的地無法達到我總是得到FD_READ觸發:

char buf[32] ; // some data to send... 
WSABUF DataBuf; 
DataBuf.len = 32; 
DataBuf.buf = (char*)&buf; 

DWORD NumBytesActualSent ; 

if(SOCKET_ERROR == WSASend(m_Socket, &DataBuf, 1, &NumBytesActualSent,0,0,0)) 
{ 
    if(WSAGetLastError() == WSAEWOULDBLOCK) // non-blocking socket - wait for send ok ? 
    { 
     // handle WSAEWOULDBLOCK... 
    } 
    else 
    { 
     // some error 
     return ; 
    } 
} 

int ret = WSAWaitForMultipleEvents(1, &m_SocketEvent, FALSE, INFINITE, FALSE) ; 


if(ret == WAIT_OBJECT_0) 
{ 
    WSANETWORKEVENTS NetworkEvents ; 
    ZeroMemory(&NetworkEvents, sizeof(NetworkEvents)) ; 
    if(SOCKET_ERROR == WSAEnumNetworkEvents(m_Socket, m_SocketEvent, &NetworkEvents)) 
    { 
     return ; // some error 
    } 
    if(NetworkEvents.lNetworkEvents & FD_READ) // Read ? 
    { 
     if(NetworkEvents.iErrorCode[FD_READ_BIT] != 0) // read not ok ? 
     { 
      // some error 
     } 
     else 
     { 
      TRACE("Read Event Triggered ! - Why ? ? ? ? ? ? ?\n") ; 
     } 
    } 
} 

任何幫助或見解將是最appriciated! 謝謝, 阿米特C.

+3

也許這就是您收到的ICMP信息(即Destination Unreachable)?檢查標題,這是一個開始的地方。 – KBart

+0

通過檢查標題(如何做),你的意思是什麼?我試圖調用WSARecv來讀取這種情況下的數據,但得到錯誤10054(「... connection was closed ...」),使用帶有FIONREAD的ioctlsocket我得到1 - meaninng我有1個字節可用於套接字接收 - 但再次WSARecv失敗。 – user1852490

回答

0

檢查真正發生的最簡單的方法是使用Wireshark來捕獲數據包。我沒有附近的Windows PC爲您提供一個完整的示例,但我的猜測是,這是一種正常行爲 - 您嘗試發送UDP數據報,它會被路由器(找不到主機)或被服務器拒絕關閉);一個ICMP消息被髮送回來告訴你有關失敗的信息,這是你收到並得到一個事件。由於沒有實際的用戶數據,因此底層堆棧將翻譯ICMP消息並通過WSARecv()返回代碼向您提供相應的錯誤消息。 「假」FD_READ事件是必要的,因爲UDP是無連接協議,並且沒有其他方式通知網絡狀態。只需添加WSARecv()的錯誤處理,您的代碼應該可以正常工作。

+0

感謝您的回覆,我使用了Wireshark,並發現在我描述的情況下,ICMP消息會傳遞到我的應用程序。 – user1852490

+0

不過,對於我來說,UDP套接字接收「false」FD_READ(以及1個字節的ioctlsocket可用數據)只是爲了讓它知道連接已斷開,這似乎有點奇怪。它也使事情複雜化,因爲我試圖創建一個處理UDP通信的類(Init,send,receive等),並且該類的用戶將獲得一個準備就緒的事件,然後嘗試讀取數據失敗;或者當這些套接字中的兩個進行通信時,然後一個正在發送,但另一個正在發送,並且一段時間後一個新的套接字與發送數據的套接字進行通信 - 此錯誤將會出現。 – user1852490

+1

如果是這樣,我想這是面向消息socekts的一些缺點...並再次感謝您的答覆 - 這有助於! – user1852490