Winsock bind() échoue avec WSAEADDRNOTAVAIL pour l'adresse de diffusion dirigée vers

Je suis en train d'ouvrir un socket UDP et d'essayer de lier ce que doit être valide réseau adresse de diffusion (192.168.202.255 : 23456), mais bind échoue avec l'erreur 10049, WSAEADDRNOTAVAIL. Si j'utilise un localhost adresse de diffusion, 127.0.0.255, il réussit.

WSAEADDRNOTAVAIL's de la documentation dit que "L'adresse demandée n'est pas valide dans son contexte. Normalement les résultats d'une tentative de lier à une adresse qui n'est pas valide pour l'ordinateur local. Cela peut également entraîner de se connecter, sendto, WSAConnect WSAJoinLeaf, ou WSASendTo lorsque la distance de l'adresse ou le port n'est pas valable pour un ordinateur distant (par exemple, l'adresse ou le port 0)." Mais je pense cette adresse, 192.168.202.255, doit être une adresse de diffusion valide en raison de l'entrée suivante lors de l'exécution de ipconfig:

Winsock bind() échoue avec WSAEADDRNOTAVAIL pour l'adresse de diffusion dirigée vers

Quel pourrait être le problème?

Code

Je suis nouveau sur Winsock la programmation et je suis sans doute une erreur grossière, mais je ne le trouve pas. Le code que j'ai pour l'instant est:

m_ulAddress = ParseIPAddress(strAddress);
//Winsock 2.2 is supported in XP
const WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA oWSAData;
const int iError = WSAStartup(wVersionRequested, &oWSAData);
if (iError != 0) {
    PrintLine(L"Error starting the network connection: WSAStartup error " + IntToStr(iError));
} else if (LOBYTE(oWSAData.wVersion) != 2 || HIBYTE(oWSAData.wVersion) != 2) {
    PrintLine(L"Error finding version 2.2 of Winsock; got version " + IntToStr(LOBYTE(oWSAData.wVersion)) + L"." + IntToStr(HIBYTE(oWSAData.wVersion)));
} else {
    m_oSocket = socket(AF_INET, SOCK_DGRAM /*UDP*/, IPPROTO_UDP);
    if (m_oSocket == INVALID_SOCKET) {
        PrintLine(L"Error creating the network socket");
    } else {
        //Socket needs to be able to send broadcast messages
        int iBroadcast = true; //docs say int sized, but boolean values
        if (setsockopt(m_oSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&iBroadcast, sizeof(iBroadcast)) != 0) {
            PrintLine(L"Error setting socket to allow broadcast addresses; error " + IntToStr(WSAGetLastError()));
        } else {
            m_oServer.sin_family = AF_INET;
            m_oServer.sin_port = m_iPort;
            m_oServer.sin_addr.S_un.S_addr = m_ulAddress;

            //!!! This is the failing call
            if (bind(m_oSocket, (sockaddr*)&m_oServer, sizeof(m_oServer)) == -1) {
                PrintLine(L"Error binding address " + String(strAddress.c_str()) + L":" + IntToStr(m_iPort) + L" to socket; error " + IntToStr(WSAGetLastError()));
            } else {
                m_bInitialisedOk = true;
            }
        }
    }
}

Commentaires

ParseIPAddress est un wrapper autour de inet_addr; inspection de la valeur de m_oServer.sin_addr.S_un.S_addr il semble être correct. m_oSocket est un SOCKET. J'ai ajouté l'appel à setsockopt puisque vous ne pouvez pas diffuser par quelque chose, mais TCP par défaut (voir la deuxième paragraphe sendto's Remarques); cet appel ne fait aucune différence. PrintLine est un wrapper pour la sortie de la console. L'étrange String /c_str() jette à la conversion et à partir de C++ wstrings à VCL des chaînes Unicode, depuis que je suis avec C++ Builder et ses VCL bibliothèques. L'adresse IP est étroite (char) de la chaîne.

La sendto de la documentation dispose que "Si un socket est ouvert, un setsockopt appel est effectué, puis un sendto appel est effectué, Windows Sockets effectue implicite de l'appel de fonction de liaison." Cela implique que bind n'est pas du tout nécessaire. Si je omettre l'appel, puis appel de sendto comme suit:

const int iLengthBytes = strMessage.length() * sizeof(char); //Narrow string
    const int iSentBytes = sendto(m_oSocket, strMessage.c_str(), iLengthBytes, 0, (sockaddr*)&m_oServer, sizeof(m_oServer));
    if (iSentBytes != iLengthBytes) {
        PrintLine(L"Error sending network message; error: " + IntToStr(WSAGetLastError()));

échoue avec l'erreur 10047, WSAEAFNOSUPPORT, "Adresse de la famille non pris en charge par la famille de protocole."

La sortie de netsh winsock show catalog (mentionnées en bas de socket's Remarques) est longue, mais ne comprennent plusieurs entrées de mentionner UDP et IPv4.

Une complication possible est que c'est en cours d'exécution dans un VMWare Fusion de l'hôte; la Fusion n'ont une drôle de configuration pour les réseaux. J'ai aussi un Cisco VPN configuré de la course de retour à mon bureau. La connexion et la déconnexion cela ne fait aucune différence.

Une chose qui me semble douteux pour moi, c'est dur de conversion de la SOCKET m_oSocket à sockaddr, mais cela semble être une pratique normale pour Winsock la programmation quand j'ai été à la lecture des exemples. De la lecture il peut être nécessaire puisque le sous-tendent l'interprétation dépend du protocole de la famille. Il semble une source potentielle d'erreur, mais je ne suis pas sûr de savoir comment l'éviter.

Des idées? Je suis perplexe 🙂

Installation

  • Windows 7 Pro sur VMWare Fusion 4.1.3
  • Le programme est compilé en 32 bits avec Embarcadero C++ Builder 2010.
  • Le programme est un programme en mode console uniquement

OriginalL'auteur David | 2013-01-08