62 votos

Obtener la dirección IP de la máquina

Esta pregunta es casi la misma que la anterior Obtener la dirección IP de la computadora local -Pregunta. Sin embargo necesito encontrar la(s) dirección(es) IP de un Máquina Linux .

Así que..: ¿Cómo puedo - programáticamente en C++ - detectar las direcciones IP del servidor de Linux en el que se está ejecutando mi aplicación. Los servidores tendrán al menos dos direcciones IP y necesito una específica (la de una red determinada (la pública)).

Estoy seguro de que hay una función simple para hacer eso, pero ¿dónde?


Para hacer las cosas un poco más claras:

  • El servidor obviamente tendrá el "localhost": 127.0.0.1
  • El servidor tendrá una dirección IP interna (de gestión): 172.16.x.x
  • El servidor tendrá una dirección IP externa (pública): 80.190.x.x

Necesito encontrar la dirección IP externa para vincular mi aplicación a ella. Obviamente también puedo vincularme a INADDR_ANY (y en realidad eso es lo que hago en este momento). Sin embargo, preferiría detectar la dirección pública.

69voto

Twelve47 Puntos 2682

Encontré la solución ioctl problemática en el os x (que es compatible con POSIX por lo que debería ser similar a linux). Sin embargo getifaddress() te permitirá hacer lo mismo fácilmente, funciona bien para mí en os x 10.5 y debería ser lo mismo abajo.

He hecho un rápido ejemplo a continuación que imprimirá todas las direcciones IPv4 de la máquina, (también deberías comprobar que el getifaddrs fue exitoso, es decir, devuelve 0).

Lo he actualizado para mostrar las direcciones IPv6 también.

#include <stdio.h>      
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h>

int main (int argc, const char * argv[]) {
    struct ifaddrs * ifAddrStruct=NULL;
    struct ifaddrs * ifa=NULL;
    void * tmpAddrPtr=NULL;

    getifaddrs(&ifAddrStruct);

    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
            // is a valid IP4 Address
            tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
        } else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
            // is a valid IP6 Address
            tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
            char addressBuffer[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
        } 
    }
    if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
    return 0;
}

22voto

Steve Baker Puntos 2220
  1. Crea un zócalo.
  2. Realiza ioctl(<socketfd>, SIOCGIFCONF, (struct ifconf)&buffer);

Lea /usr/include/linux/if.h para información sobre las estructuras ifconf e ifreq. Esto debería darle la dirección IP de cada interfaz del sistema. También lea /usr/include/linux/sockios.h para obtener información adicional sobre ioctls.

17voto

4dan Puntos 189

Me gusta la respuesta de jjvainio . Como dice Zan Lnyx, utiliza la tabla de enrutamiento local para encontrar la dirección IP de la interfaz ethernet que se utilizaría para una conexión a un host externo específico. Usando un enchufe UDP conectado, puede obtener la información sin enviar ningún paquete. El enfoque requiere que se elija un host externo específico. La mayoría de las veces, cualquier IP pública conocida debería servir. Me gusta la dirección del servidor DNS público de Google 8.8.8.8 para este propósito, pero puede haber ocasiones en las que quieras elegir una IP de host externo diferente. Aquí hay un código que ilustra el enfoque completo.

void GetPrimaryIp(char* buffer, size_t buflen) 
{
    assert(buflen >= 16);

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    assert(sock != -1);

    const char* kGoogleDnsIp = "8.8.8.8";
    uint16_t kDnsPort = 53;
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
    serv.sin_port = htons(kDnsPort);

    int err = connect(sock, (const sockaddr*) &serv, sizeof(serv));
    assert(err != -1);

    sockaddr_in name;
    socklen_t namelen = sizeof(name);
    err = getsockname(sock, (sockaddr*) &name, &namelen);
    assert(err != -1);

    const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, buflen);
    assert(p);

    close(sock);
}

11voto

jjvainio Puntos 203

Como has descubierto, no existe una única "dirección IP local". Aquí está cómo encontrar la dirección local que puede ser enviada a un host específico.

  1. Crear un enchufe UDP
  2. Conecte el enchufe a una dirección externa (el anfitrión que eventualmente recibirá la dirección local)
  3. Use el getockname para obtener la dirección local

9voto

unwind Puntos 181987

Esta página muestra una solución usando las dos funciones gethostname() junto con gethostbyname() . El primero te dice el nombre de la máquina local, el segundo busca la(s) dirección(es) IP de ese nombre. Usar el segundo con "localhost" no funciona, que típicamente sólo te da 127.0.0.1.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X