当没有可用的目标时,WSASend for UDP套接字会触发FD_READ

时间:2013-02-04 06:20:40

标签: c++ mfc network-programming winsock2

我正在为UDP套接字类编写C ++代码来处理基本操作(例如连接,发送和接收数据)。我尝试使用WSAEventSelect的网络事件机制来处理与套接字相关的这些基本操作。 当我使用WSASend将数据发送到接收数据的(UDP)目的地时,一切顺利。 但是,当我使用WSASend将数据发送到不存在(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") ;
        }
    }
}

任何帮助或见解都会受到最多的关注! 谢谢, 阿米特C.

1 个答案:

答案 0 :(得分:0)

检查实际发生情况的最简单方法是使用Wireshark来捕获数据包。我没有附近的Windows PC为您提供完整的示例,但我的猜测是这是一种正常的行为 - 您尝试发送UDP数据报,它被路由器(未找到主机)丢弃或被服务器拒绝(套接字关闭);将发回ICMP消息以通知您失败,这是您收到的并获得活动的消息。由于没有实际的用户数据,底层堆栈会转换ICMP消息,并通过 WSARecv()返回代码为您提供相应的错误消息。 “假”FD_READ事件是必要的,因为UDP是无连接协议,并且没有其他方式来通知网络状态。只需为 WSARecv()添加错误处理,您的代码就可以正常工作。