Получите IP-адрес машины

91
задан Community 23 May 2017 в 12:34
поделиться

7 ответов

Я нашел ioctl решение проблематичным на OS x (который является POSIX, совместимым, так должен быть similiar к Linux). Однако getifaddress () позволит Вам сделать то же самое легко, это хорошо работает для меня на OS x 10.5 и должно быть тем же ниже.

я сделал быстрый пример, ниже которого распечатает весь адрес IPv4 машины, (необходимо также проверить, что getifaddrs был успешен т.е. возвращается 0).

я обновил его выставочные адреса IPv6 также.

#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) {
            continue;
        }
        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;
}
99
ответ дан Josh Kelley 24 November 2019 в 06:46
поделиться
  1. Создают сокет.
  2. Работают ioctl(<socketfd>, SIOCGIFCONF, (struct ifconf)&buffer);

Read /usr/include/linux/if.h для получения информации о ifconf и ifreq структуры. Это должно дать Вам IP-адрес каждого интерфейса в системе. Также читайте /usr/include/linux/sockios.h для дополнительного ioctls.

28
ответ дан Vinay Shukla 24 November 2019 в 06:46
поделиться

Поскольку Вы нашли, там не такая вещь как единственный "локальный IP-адрес". Вот то, как узнать локальный адрес, который может быть отослан в определенный хост.

  1. Создают сокет UDP
  2. Подключение сокет к внешнему адресу (хост, который в конечном счете получит локальный адрес)
  3. Использование getsockname для получения локального адреса
14
ответ дан jjvainio 24 November 2019 в 06:46
поделиться

В дополнение к тому, что сказал Steve Baker, можно найти описание SIOCGIFCONF ioctl в netdevice (7) страница справочника .

, Как только у Вас есть список всех IP-адресов на хосте, необходимо будет использовать специализированную логику для отфильтровывания адресов, которые Вы не хотите и надеетесь, что имеете один IP-адрес в запасе.

4
ответ дан camh 24 November 2019 в 06:46
поделиться

Можно сделать некоторую интеграцию с завихрением как что-то столь же легкое как: curl www.whatismyip.org от оболочки получит Вас Ваш глобальный IP. Вы довольно уверены в некотором внешнем сервере, но Вы всегда будете то, если Вы будете позади NAT.

1
ответ дан 24 November 2019 в 06:46
поделиться

Мне нравится ответ jjvainio . Как говорит Зан Линкс, он использует локальную таблицу маршрутизации, чтобы найти IP-адрес интерфейса Ethernet, который будет использоваться для подключения к определенному внешнему хосту. Используя подключенный UDP-сокет, вы можете получать информацию, фактически не отправляя никаких пакетов. Подход требует, чтобы вы выбрали конкретный внешний хост. В большинстве случаев любой хорошо известный публичный IP-адрес подойдет. Для этой цели мне нравится общедоступный адрес DNS-сервера Google 8.8.8.8, но могут быть случаи, когда вы захотите выбрать другой IP-адрес внешнего хоста. Вот код, который полностью иллюстрирует подход.

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);
}
24
ответ дан 24 November 2019 в 06:46
поделиться

Не жестко кодируйте: это то, что может измениться. Многие программы выясняют, к чему привязываться, читая файл конфигурации и делая все, что в нем говорится. Таким образом, если вашей программе когда-нибудь в будущем потребуется привязка к чему-то, что не является общедоступным IP-адресом, она сможет это сделать.

4
ответ дан 24 November 2019 в 06:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: