Почему моя структура addrinfo заполнена мусором после вызова getaddrinfo ()? - PullRequest
0 голосов
/ 24 марта 2020

где-то в следующем коде есть ошибка, но я до сих пор не мог ее понять.

    struct addrinfo hints, *addrinfo;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_protocol = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;

    if (int result{ getaddrinfo("192.168.178.68", "5642", &hints, &addrinfo) }; result != 0) {
        throw "Please create an exception here";
    }

    auto debug = reinterpret_cast<sockaddr_in*> (addrinfo);
    std::cout << inet_ntoa(debug->sin_addr) << std::endl << debug->sin_family << std::endl
        << debug->sin_port << std::endl;

Последняя строка этой строки выводит данные об мусоре, я ожидал, что она выведет значения, которые я передал в вызове getaddrinfo (). Мне удалось "вручную" настроить структуру sockaddr_in, которая ведет себя правильно, но я все же хотел бы выяснить, почему эта не работает. Я предполагаю, что это связано с актерами.

Спасибо за любую помощь!

Ответы [ 2 ]

3 голосов
/ 24 марта 2020

Вам необходимо использовать поля ai_addr и ai_addrlen структуры addrinfo, а не пытаться трактовать сам addrinfo как совершенно другой тип. Что-то вроде:

char host[NI_MAXHOST], port[NI_MAXSERV];
int err;
if ((err = getnameinfo(addrinfo->ai_addr, addrinfo->ai_addrlen,
                       host, sizeof host, port, sizeof port,
                       NI_NUMERICHOST | NI_NUMERICPORT)) == 0) {
  std::cout << host << '\n' << addrinfo->ai_family << '\n'
            << port << '\n';
} else {
  std::cerr << "Error: " << gai_strerror(err) << '\n';
}

Эта строка также является проблемой:

hints.ai_protocol = AF_UNSPEC;

Из справочной страницы :

ai_protocol В этом поле указывается протокол для возвращенных адресов сокетов. Значение 0 в этом поле указывает, что адреса сокетов с любым протоколом могут быть возвращены getaddrinfo().

AF_UNSPEC следует использовать только с полем ai_family, если вы не хотите возвращать только адреса IPv4 или IPv6, но возможно оба.

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

Вы вводите тип addrinfo на sockaddr_in, что неправильно. addrinfo само по себе не является sockaddr_in, но может указать на sockaddr_in. getaddrinfo() возвращает связанный список из 1 или более структур addrinfo, каждая из которых указывает на соответствующую структуру sockaddr_... в своем поле ai_addr. Вам нужно перебрать этот список, используя каждую из этих структур по мере необходимости.

Кроме того, вы используете AF_UNSPEC с полем hints.ai_protocol, но это не значение протокола, его следует использовать только с поле hints.ai_family. Допустимое значение ai_protocol для сокета SOCK_DGRAM будет, например, IPPROTO_UDP. Просто так получается, что AF_UNSPEC имеет значение 0, а установка hints.ai_protocol на 0 указывает getaddrinfo() возвращать адреса для любого протокола.

Попробуйте вместо этого:

addrinfo hints, *addrs;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;

int result = getaddrinfo("192.168.178.68", "5642", &hints, &addrs);
if (result != 0) {
    throw "Please create an exception here";
}

for(auto addr = addrs; addr != nullptr; addr = addr->ai_next)
{
    auto in4 = reinterpret_cast<sockaddr_in*>(addr->ai_addr);
    std::cout << in4->sin_family << std::endl
              << inet_ntoa(in4->sin_addr) << std::endl
              << ntohs(in4->sin_port) << std::endl;
}

freeaddrinfo(addrs);

При этом, если вы установите hints.ai_family на AF_UNSPEC, тогда getaddrinfo() может вернуть список, содержащий EITHER sockaddr_in ИЛИ sockaddr_in6 структур , ИЛИ ОБА :

addrinfo hints, *addrs;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;

int result = getaddrinfo("192.168.178.68", "5642", &hints, &addrs);
if (result != 0) {
    throw "Please create an exception here";
}

char ipaddrbuf[46];
for(auto addr = addrs; addr != nullptr; addr = addr->ai_next)
{
    switch (addr->ai_family /* or: addr->ai_addr->sa_family */ )
    {
        case AF_INET:
        {
            auto in4 = reinterpret_cast<sockaddr_in*>(addr->ai_addr);
            std::cout << in4->sin_family << std::endl
                      << inet_ntop(AF_INET, &(in4->sin_addr), ipaddrbuf, sizeof(ipaddrbuf)) << std::endl
                      << ntohs(in4->sin_port) << std::endl;
            break;
        }

        case AF_INET6:
        {
            auto in6 = reinterpret_cast<sockaddr_in6*>(addr->ai_addr);
            std::cout << in6->sin6_family << std::endl
                      << inet_ntop(AF_INET6, &(in6->sin6_addr), ipaddrbuf, sizeof(ipaddrbuf)) << std::endl
                      << ntohs(in6->sin6_port) << std::endl;
            break;
        }
    }
}

freeaddrinfo(addrs);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...