C - getaddrinfo () - PullRequest
       56

C - getaddrinfo ()

0 голосов
/ 09 марта 2020

Может ли кто-нибудь помочь мне получить IP-адреса google.com?

. Я не могу найти хороший ресурс по этому вопросу.
В большинстве руководств по C сетевому программированию создаются клиентский сокет и сокет сервера на том же компьютере. (Я не знаю, в какой ситуации это имело бы смысл)
И ни один из кодов на beej.us не работал для меня.

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>

int main(void)
{
    struct addrinfo* res = NULL;
    getaddrinfo("google.com", "443", 0, &res);

    struct addrinfo* i;

    for(i=res; i!=0; res=res->ai_next)
    {
        printf("%s\n", res->ai_addr->sa_data);
    }
}

Выход:

�
�
�
���$u
���$u
���$u
���"u
���"u
���"u
��� u
��� u
��� u
���&u
���&u
���&u
Segmentation fault

Ответы [ 2 ]

1 голос
/ 09 марта 2020

Во-первых, вы никогда не измените i внутри l oop, поэтому вы получите бесконечное l oop. Вам нужно изменить на оператор l oop на:

for(i=res; i!=NULL; i=i->ai_next)

Что касается вывода, поле ai_addr имеет тип struct sockaddr *, который является указателем на общую структуру адреса сокета c , а его поле sa_data является просто двоичным двоичным объектом данных для этого адреса, а не строкой для печати. ​​

Чтобы правильно распечатать эти значения, вам нужно inet_ntop функция. Во-первых, вам нужно проверить ai_addr->sa_family, чтобы увидеть, является ли это адрес IPv4 или IPv6. Затем вам нужно привести ai_addr к struct sockaddr_in * для IPv4 или struct sockaddr_in6 * для IPv6, затем передать поле sin_addr или sin6_addr соответственно в inet_ntop вместе с семейством адресов, чтобы преобразовать его в строка.

for(i=res; i!=NULL; i=i->ai_next)
{
    char str[INET6_ADDRSTRLEN];
    if (i->ai_addr->sa_family == AF_INET) {
        struct sockaddr_in *p = (struct sockaddr_in *)i->ai_addr;
        printf("%s\n", inet_ntop(AF_INET, &p->sin_addr, str, sizeof(str)));
    } else if (i->ai_addr->sa_family == AF_INET6) {
        struct sockaddr_in6 *p = (struct sockaddr_in6 *)i->ai_addr;
        printf("%s\n", inet_ntop(AF_INET6, &p->sin6_addr, str, sizeof(str)));
    }
}

Вывод:

172.217.10.238
172.217.10.238
172.217.10.238
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
1 голос
/ 09 марта 2020

В этом утверждении i никогда не изменяется в теле l oop, и, поскольку оно не инициализировано, оно никогда даже не входит в l oop:

for(i=res; i!=0; res=res->ai_next)
{
    printf("%s\n", res->ai_addr->sa_data);
}

Кроме того, вы пропустить несколько других частей. Следующие шаги являются частью полного примера, связанного ниже:

Создайте следующие экземпляры struct addrinfo:

struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;

Затем инициализируйте Winsock

   // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

Настройте hints address info структура

ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

Звоните getaddrinfo

dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result);
if ( dwRetval != 0 ){//handle error}

Теперь, например, исходя из вышеизложенного, ваш l oop будет выглядеть так:

   for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {//

Ввод "www.google.com" 0 в командной строке для полного примера (ссылка ниже) будет выглядеть примерно так:
enter image description here

Это полное Windows пример здесь . Примечание : ошибка в коде, то есть ptr-> ai_cannonname может быть нулевой с "www.google.com", поэтому перед вызовом измените эту строку для проверки:

if(ptr->ai_canonname) printf("\tCanonical name: %s\n", ptr->ai_canonname);

Полный Linux пример здесь .

...