Frage

  1. Sie haben mehrere Netzwerkadapter.
  2. Binden Sie einen UDP-Socket an einen lokalen Port, ohne eine Adresse anzugeben.
  3. Empfangen Sie Pakete auf einem der Adapter.

Wie erhalten Sie die lokale IP-Adresse des Adapters, der das Paket empfangen hat?

Die Frage lautet: "Wie lautet die IP -Adresse aus dem Empfängeradapter?" nicht die Adresse des Absenders, die wir in die erhalten

receive_from( ..., &senderAddr, ... );

Anruf.

War es hilfreich?

Lösung

Sie könnten alle Netzwerkadapter aufzählen, ihre IP-Adressen ermitteln und den von der Subnetzmaske abgedeckten Teil mit der Absenderadresse vergleichen.

Wie:

IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
    foreach( adapter in EnumAllNetworkAdapters() )
    {
        adapterSubnet = adapter.subnetmask & adapter.ipaddress;
        senderSubnet = adapter.subnetmask & senderAddr;
        if( adapterSubnet == senderSubnet )
        {
            return adapter.ipaddress;
        }
    }
}

Andere Tipps

Tag auch,

Ich gehe davon aus, dass Sie Ihre Bindung mit INADDR_ANY durchgeführt haben, um die Adresse anzugeben.

Wenn dies der Fall ist, ist die Semantik von INADDR_ANY so, dass ein UDP-Socket auf dem Port erstellt wird, der auf allen Ihren Schnittstellen angegeben ist.Der Socket empfängt alle Pakete, die an alle Schnittstellen am angegebenen Port gesendet werden.

Beim Senden über diesen Socket wird die Schnittstelle mit der niedrigsten Nummer verwendet.Das Adressfeld des ausgehenden Absenders wird auf die IP-Adresse der ersten verwendeten ausgehenden Schnittstelle gesetzt.

Die erste ausgehende Schnittstelle wird als Sequenz definiert, wenn Sie ifconfig -a ausführen.Es wird wahrscheinlich eth0 sein.

HTH.

Prost, Rob

Die Lösung von Timbo geht davon aus, dass die Adressbereiche eindeutig sind und sich nicht überschneiden.Obwohl dies normalerweise der Fall ist, handelt es sich nicht um eine generische Lösung.

Es gibt eine hervorragende Implementierung einer Funktion, die genau das tut, was Sie im Steven -Buch "UNIX -Netzwerkprogrammierung" (Abschnitt 20.2) zur Verfügung gestellt haben. Dies ist eine Funktion, die auf recvmsg () statt recvfrom () basiert.Wenn in Ihrem Socket die Option IP_RECVIF aktiviert ist, gibt recvmsg() den Index der Schnittstelle zurück, auf der das Paket empfangen wurde.Daraus lässt sich dann die Zieladresse ermitteln.

Der Quellcode ist verfügbar Hier.Die betreffende Funktion ist „recvfrom_flags()“.

Leider sind die API-Aufrufe sendto und recvfrom grundsätzlich fehlerhaft, wenn sie mit Sockets verwendet werden, die an „Any IP“ gebunden sind, da sie kein Feld für lokale IP-Informationen haben.

Was können Sie also dagegen tun?

  1. Sie können es erraten (z. B. anhand der Routing-Tabelle).
  2. Sie können eine Liste lokaler Adressen abrufen und an jede lokale Adresse einen separaten Socket binden.
  3. Sie können neuere APIs verwenden, die diese Informationen unterstützen.Dies besteht aus zwei Teilen: Erstens müssen Sie die relavent-Socket-Option (ip_recvif für IPv4, ipv6_recvif für IPv6) verwenden, um dem Stack mitzuteilen, dass Sie diese Informationen benötigen.Dann müssen Sie eine andere Funktion (recvmsg unter Linux und mehreren anderen Unix-ähnlichen Systemen, WSArecvmsg unter Windows) verwenden, um das Paket zu empfangen.

Keine dieser Optionen ist großartig.Raten führt natürlich manchmal zu falschen Antworten.Das Binden separater Sockets erhöht die Komplexität Ihrer Software und verursacht Probleme, wenn sich die Liste der lokalen Adressen während der Ausführung Ihres Programms ändert.Die neueren APIs stellen die richtige technische Lösung dar, können jedoch die Portabilität beeinträchtigen (Insbesondere sieht es so aus, als ob WSArecvmsg unter Windows XP nicht verfügbar ist.) und erfordert möglicherweise Änderungen an der von Ihnen verwendeten Socket-Wrapper-Bibliothek.

Edit sieht so aus, als hätte ich mich geirrt, die MS-Dokumentation scheint irreführend zu sein und WSArecvmsg ist unter Windows XP verfügbar.Sehen https://stackoverflow.com/a/37334943/5083516

ssize_t
     recvfrom(int socket, void *restrict buffer, size_t length, int flags,
         struct sockaddr *restrict address, socklen_t *restrict address_len);

     ssize_t
     recvmsg(int socket, struct msghdr *message, int flags);

[..]
     If address is not a null pointer and the socket is not connection-oriented, the
     source address of the message is filled in.

Tatsächlicher Code:

int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);

fprintf(stdout, "Read %d bytes on local address %s\n", nbytes, inet_ntoa(bindaddr.sin_addr.s_addr));

hoffe das hilft.

Versuche dies:

gethostbyname("localhost");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top