Розетки. Установка поля s_addr структуры sockaddr_in - PullRequest
1 голос
/ 15 октября 2019

Я пытаюсь проверить код, который подключается к удаленному хосту с данными, данными функцией gethostbyname () . В примерах я обнаружил, что они делают следующее:

struct hostent* pHostent = gethostbyname(host);
struct sockaddr_in remoteAddr;
// ... code
remoteAddr.sin_addr.s_addr = ((struct in_addr*) (pHostent->h_addr))->s_addr;
// ... more code

Я пытаюсь понять, что здесь делается.

  1. Это законно, поскольку типы данных различны? Может быть, memcpy () следовало бы использовать?

  2. Почему это работает? То есть какие данные на самом деле находятся в обоих местах?

1 Ответ

3 голосов
/ 15 октября 2019

Мы можем начать с просмотра фактических структурных схем:

struct hostent {
   char  *h_name;
   char **h_aliases;
   int    h_addrtype
   int    h_length;
   char **h_addr_list;
}
#define h_addr h_addr_list[0]
struct sockaddr_in {
    short            sin_family;
    unsigned short   sin_port;
    struct in_addr   sin_addr;
    char             sin_zero[8];
};
struct in_addr {
    uint32_t       s_addr;    // IPv4 address
};

Функция gethostbyname() может выдавать адреса IPv4 или IPv6, в зависимости от значения h_addrtype. Таким образом, h_addr_list должен иметь возможность хранить адреса IPv4 или IPv6. Для этого адреса хранятся в виде необработанной памяти, на которую указывают char* указатели. Чтобы получить фактический адрес, вам нужно привести память к правильному типу адреса, как вы нашли в своем коде:

remoteAddr.sin_addr.s_addr = ((struct in_addr*) (pHostent->h_addr))->s_addr;

Итак, чтобы ответить на ваши вопросы:

  1. Типы указателей различны, но указанные данные имеют одинаковый тип.
  2. Нет, данные находятся только в одном месте, на них просто ссылаются указатели другого типа.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...