0

基本的な操作 (接続、データの送受信など) を処理する 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.

4

1 に答える 1

0

実際に何が起こっているかを調べる最も簡単な方法は、Wiresharkを使用してパケットをキャプチャすることです。完全な例を提供できる Windows PC が近くにありませんが、これは通常の動作であると推測されます。UDP データグラムを送信しようとすると、ルーターによってドロップされるか (ホストが見つからない)、サーバーによって拒否されます (ソケット閉まっている); 失敗について通知するために ICMP メッセージが送り返されます。これは、受信してイベントを取得するためのものです。実際のユーザー データがないため、基礎となるスタックは ICMP メッセージを変換し、 WSARecv()リターン コードを介して適切なエラー メッセージを提供します。UDP はコネクションレス プロトコルであり、ネットワークの状態を通知する手段が他にないため、「偽」の FD_READ イベントが必要です。WSARecv()のエラー処理を追加するだけですあなたのコードは正常に動作するはずです。

于 2013-02-04T11:40:04.857 に答える