структуры sockaddr как объединение

Я ищу сводную информацию о структурах адресов сокетов, интерпретируемых как объединение, чтобы иметь полный обзор. Единственные вопросы и ответы, подобные этому, которые я нашел, - это объединение Sockaddr и getaddrinfo() , но они не суммируют структуры.

Как выглядит объединение структур адреса сокета и какие структуры адреса в деталях используются?

1 ответ

Мне не хватает удобной сводки структур адресов сокетов. Да, я знаю, что в Интернете существует множество примеров, но я не смог найти тот, который собрал бы все в одном месте.

Структуры адресов сокетов перекрывают друг друга в памяти. Поэтому их можно объявить как тип объединения. По спецификации,sockaddr_storageструктура достаточно велика, чтобы вместить все структуры, поэтому она определяет размер объединения. При использовании объединения больше нет необходимости в приведении типов (за исключением(sockaddr*)для аргументов функции).

      using sockaddr_t = union {
    sockaddr_storage ss;
    sockaddr_in6     sin6;
    sockaddr_in      sin;
    sockaddr         sa;
};

struct sockaddr_storage {
    sa_family_t      ss_family;
    // Following field(s) are implementation specific
    // only for padding to mostly 128 bytes.
    // No information usable.
};

struct sockaddr_in6 {
    sa_family_t      sin6_family;   // AF_INET6.
    in_port_t        sin6_port;     // Port number.
    uint32_t         sin6_flowinfo; // IPv6 traffic class and flow info.
    struct in6_addr  sin6_addr;     // IPv6 address.
    uint32_t         sin6_scope_id; // Set of interfaces for a scope.
};

struct sockaddr_in {
    sa_family_t      sin_family;    // AF_INET.
    in_port_t        sin_port;      // Port number.
    struct in_addr   sin_addr;      // IP address.
};

struct sockaddr {
    sa_family_t      sa_family;     // Address family.
    // char          sa_data[];     // Socket address (variable-length data).
};

struct in6_addr {
    uint8_t s6_addr[16];
};

struct in_addr {
    in_addr_t s_addr;
};

using sa_family_t = unsigned short int;
using in_addr_t = uint32_t;
using in_port_t = uint16_t;

Примеры:

      #include <netdb.h> // for sockaddr structures
#include <cstring> // for memcmp()
#include <cassert>

int main() {
    sockaddr_t saddr{};

    assert(saddr.ss.ss_family == saddr.sin6.sin6_family);
    assert(saddr.ss.ss_family == saddr.sin.sin_family);
    assert(saddr.ss.ss_family == saddr.sa.sa_family);

    if (saddr.ss.ss_family == AF_INET6) {
        in_port_t port6 = saddr.sin6.sin6_port;
        in6_addr addr6 = saddr.sin6.sin6_addr;

        // Check if sin6_addr is null
        uint8_t s6_addr0[16]{};
        bool res =
            (memcmp(saddr.sin6.sin6_addr.s6_addr, s6_addr0, sizeof(s6_addr0)) == 0);
    }

   if (saddr.ss.ss_family == AF_INET) {
        in_port_t port = saddr.sin.sin_port;
        in_addr_t addr = saddr.sin.sin_addr.s_addr;
    }

    // sockaddr is only used for type casting on function arguments
    if (saddr.ss.ss_family == AF_INET6) {
        int sockfd = socket(saddr.ss.ss_family, SOCK_DGRAM, 0);
        socklen_t len = sizeof(saddr.sin6);
        int ret = getsockname(sockfd, (sockaddr*)&saddr, &len);
    }
}

Более полезный пример вы можете найти в Sockaddr Union и getaddrinfo().

Использованная литература:

Другие вопросы по тегам