2013-04-10 3 views
7

Ich möchte die IP-Adresse des Computers erhalten, auf dem mein Programm gestartet wird, um es dann an einen Client senden zu können, aber ich bekomme immer 0.0.0.1 anstelle der realen IP-Adresse (wie zum Beispiel 127.0.0.1) .Wie bekomme ich eine eigene IP-Adresse mit einer Socket-Adresse?

Ich bin derzeit in der Lage, den Port zu bekommen, aber nicht die IP-Adresse.

Wie kann ich es bekommen?

Die beste Lösung wäre es, mit einem sockaddr_in zu bekommen. Hier ist, was ich gerade tun:

int open_connection(char* ip, int* port) 
{ 
    int     sock; 
    struct sockaddr_in sin; 
    socklen_t    len; 
    int     i; 

    i = 0; 
    len = sizeof(sin); 
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    return (-1); 
    bzero(&sin, sizeof(struct sockaddr_in)); 
    sin.sin_family = AF_INET; 
    if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) 
    perror("Error on bind"); 
    if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0) 
    perror("Error on getsockname"); 
    strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0 
    *port = sin.sin_port; 
    return (sock); 
} 

EDIT: Ich verstehe, ich war auf dem falschen Weg mit meiner Denkweise gehen. Also meine Frage ist: Was ist der beste Weg, um Ihre eigene IP-Adresse zu bekommen?

+1

Wenn der Client mit Ihnen spricht ... hat er bereits Ihre IP-Adresse. Ich bin verwirrt, warum Sie es explizit senden müssen. – Pyrce

+1

@Pyrce Ich mache einen FTP-Server, und wenn ich den passiven Modus betrete, muss ich die IP-Adresse und den Port senden, den der Server abhört ... Selbst wenn es die gleiche IP-Adresse ist ... –

+2

Vielleicht ist das alt Frage? http://stackoverflow.com/questions/212528/get-the-ip-address-of-the-machine Ich denke, Bindung an 0.0.0.0 ist eine spezielle Sache, obwohl, was bedeutet, an alle IP-Adressen binden - ich bezweifle Sie würde nichts anderes aus der Bindung holen, da das das ist, was Sie übergeben haben. – Rup

Antwort

10

Wenn Sie bind() einen Socket zu 0.0.0.0, das ist die einzige IP-Adresse, die der Socket beim Aufruf getsockname() verfügbar ist. Dies bedeutet, dass der Socket an alle lokalen Schnittstellen gebunden ist. Um eine bestimmte IP von einem Socket zu erhalten, muss sie an eine bestimmte IP gebunden sein.

Die Verwendung der Socket-API zum Abrufen der lokalen IP-Adresse (n) der Maschine ist ohnehin der falsche Ansatz. Ein häufiger Fehler ist es, gethostname() mit gethostbyname() oder getaddrinfo() zu verwenden, um die lokale IP-Liste zu erhalten. Normalerweise funktioniert das, aber es hat einige versteckte Fehler, die falsche Informationen verursachen können, aber die Leute neigen dazu, diese Tatsache zu ignorieren oder gar nicht erst davon zu wissen (ich wusste es jahrelang nicht, aber dann besser gelernt).

Stattdessen sollten Sie plattformspezifische APIs zum Aufzählen der lokalen Netzwerkschnittstellen verwenden. Das wird zuverlässigere Informationen liefern. Windows hat GetAdaptersInfo() und GetAdaptersAddresses(). Andere Plattformen haben getifaddrs(). Diese werden Ihnen sagen, welche lokalen IPs verfügbar sind. Sie können dann bind() einen Socket zu 0.0.0.0, um Clients auf einer dieser IPs oder bind() zu einer bestimmten IP zu akzeptieren Clients nur auf dieser IP akzeptieren.

+0

Können Sie bitte die "* ... versteckten Gotchas ... *" in 'getaddrinfo()' näher erläutern? – alk

+0

'gethostbyname()' und 'getaddrinfo()' verwenden DNS-Lookups, um Hostnamen in IPs aufzulösen. Sie sind nicht dazu gedacht, Informationen über localhost abzurufen. Es ist möglich, dass a) ein Benutzer den DNS-Cache des Hosts (Hosts-Datei usw.) ändert/beschädigt und b) der Hostname eines PCs so konfiguriert wird, dass er überhaupt keine IP hat oder mehreren IPs zuzuordnen ist, die möglicherweise nicht alle gehören an den PC (denke Lastverteilung, etc). Diese Funktionen sind nicht 100% ig garantiert, dass gültige lokale IPs zurückgegeben werden, wenn in allen Setups ein lokaler Hostname übergeben wird. Funktionen wie 'GetAdaptersInfo()' und 'getifsaddrs()' sind stattdessen für diesen Zweck gedacht. –

+0

Oh ja, das ** externe ** DNS ist das, worauf du dich im Grunde beziehst. Ich stimme dem zu. Danke für die Klärung. – alk

4

Mit der Sockets-API können Sie die Ihren Netzwerkschnittstellen zugewiesenen IP-Adressen auflisten, aber Sie erfahren nicht, was Sie "echte IP" nennen, wenn Sie sich hinter einem Router mit dem Internet verbinden.

Die einzige Möglichkeit, es zu wissen, ist, jemanden nach draußen zu fragen. Das tun Server wie FileZilla FTP Server. Sie weisen Sie an, die URL zu einem "ip.php" -Skript wie this one in den Servereinstellungen zu konfigurieren, damit es das Internet fragen kann, wie seine öffentliche IP-Adresse im Passiv-Modus verwendet werden soll.

Sie können auch die Verwendung von STUN in Betracht ziehen, ein Protokoll, das in VoIP weit verbreitet ist, um öffentliche IP zu entdecken.

+1

+1. Wenn OP mehr Optionen möchte, mag ich persönlich [ifconfig.me] (http://ifconfig.me) und [canhazip.com] (http://canhazip.com). – jweyrich

+0

Danke, das ist nicht für meine aktuellen Bedürfnisse (es ist ein Schulprojekt, und es ist nicht beabsichtigt, aus dem Internet zu arbeiten). Ich werde sehen, ob ich Zeit habe, es umzusetzen. –

0

Sie könnten ioctl nennen (Socke, SIOCGIFADDR, adr)

siehe netdevice (7)

0

Nach @Remy Lebeau ‚s Antwort, die ich eine Funktion geschrieben, die aktuelle Adresse des Geräts zurückzukehren. Ich habe das nur auf macOS High Sierra getestet.

interfaec kann alles unter lo0 sein, en0 usw.

ipVersion kann AF_INET oder AF_INET6 sein.

long int getInternalAddress(char* interface, sa_family_t ipVersion) 
{ 
    struct ifaddrs *ifaddrHead, *ifaddr; 
    /* int_8 */ 
    sa_family_t family; 
    int n; 
    char *interfaceName; 

    if (getifaddrs(&ifaddrHead) != 0) 
    { 
    fprintf(stderr, "ifaddrs error"); 
    } 

    /* iterate through address list */ 
    for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++) 
    { 
    family = ifaddr->ifa_addr->sa_family; 
    interfaceName = ifaddr->ifa_name; 

    if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue; 

    struct sockaddr *addr = ifaddr->ifa_addr; 
    struct sockaddr_in* addr_in = (struct sockaddr_in*) addr; 
    long int address = addr_in->sin_addr.s_addr; 

    freeifaddrs(ifaddrHead); 

    return address; 
    } 

    freeifaddrs(ifaddrHead); 

    return 0; 
} 

es zu verwenden,

int main() 
{ 
    long int address = getInternalAddress((char*) &"en0", AF_INET); 
    printf("%li\n", address); 

    return 0; 
} 

Ich bin noch ein Anfänger in C, wenn es etwas falsch bitte sagen Sie mir.

Verwandte Themen