2015-09-17 15 views
5
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 

Faktyczna struktura przekazana dla argumentu addr będzie zależeć od rodziny adresów. Struktura sockaddr jest definiowana jako coś w rodzaju:Jaki jest cel pola sa_data w sockaddr?

struct sockaddr { 
    sa_family_t sa_family; 
    char  sa_data[14]; 
} 

więc dla adresu IPv4 (AF_INET), rzeczywista struktura, która będzie przekazywana jest taka:

/* Source http://linux.die.net/man/7/ip */ 

struct sockaddr_in { 
    sa_family_t sin_family; /* address family: AF_INET */ 
    in_port_t  sin_port; /* port in network byte order */ 
    struct in_addr sin_addr; /* internet address */ 
}; 

/* Internet address. */ 
struct in_addr { 
    uint32_t  s_addr;  /* address in network byte order */ 
}; 

Czy kod wiążą odczytać wartość sockaddr.sa_family i w zależności od wartości, którą znajdzie, następnie odrzuci strukturę sockaddr do odpowiedniej struktury, takiej jak sockaddr_in?

Dlaczego sa_data ma 14 znaków? Jeśli rozumiem poprawnie, pole sa_data jest tylko polem, które będzie wystarczająco duże, aby pasowało do wszystkich typów rodzin adresów? Prawdopodobnie pierwotni projektanci przewidzieli, że 14 znaków będzie wystarczająco szerokie, aby pasowały do ​​wszystkich przyszłych typów.

+0

https://en.wikipedia.org/wiki/Type_punning – user3386109

Odpowiedz

5

Według glibc manual:

Długość 14 sa_data jest w zasadzie dowolna.

A FreeBSD developers handbook wymienia następujące:

Proszę zwrócić uwagę na niejasności w którym pole sa_data deklarowane, tylko jako tablica 14 bajtów, z komentarzem podpowiedzi nie może być ponad 14 z nich.

Ta ogólnikowość jest dość celowa. Gniazda to bardzo wydajny interfejs . Podczas gdy większość ludzi może myśleć o tym jako o interfejsie internetowym - i większość aplikacji prawdopodobnie używa go do tego dzisiejszych gniazd może być używany do prawie każdego rodzaju komunikacji międzyprocesowej , z czego Internet (a dokładniej , IP) to tylko .

Tak, pole sa_family służy do rozpoznania, jak traktować struct przekazywane (która jest odlewana do struct sockaddr* w wywołaniu do wiązania). Możesz przeczytać więcej o tym, jak to działa również w FreeBSD developers handbook.

I rzeczywiście istnieją „polimorficznych” (sub) rodzaje sockaddr, w którym sa_data zawiera więcej niż 16 bajtów, na przykład:

struct sockaddr_un { 
    sa_family_t sun_family;    /* AF_UNIX */ 
    char  sun_path[108];   /* pathname */ 
}; 
3

sockaddr struktura jest wykorzystywane jako rekord z wariantami. Czytając pole sa_family, można go rzucić na strukturę odpowiedniej postaci.

14 bajtów jest dowolne. Jest wystarczająco duży, aby pomieścić adresy IPv4, ale nie jest wystarczająco duży, aby pomieścić adresy IPv6. Istnieje również struktura sockaddr_storage, która jest wystarczająco duża dla obu. Czytając dokumentację Microsoftu pod numerem SOCKADDR_STORAGE, ma on 128 bajtów, czyli tyle, ile potrzeba dla IPv6. Sprawdzając niektóre nagłówki linuksowe, wydaje się, że jest tam co najmniej tak duży.

Dla porównania, struct IPv6 jest:

struct sockaddr_in6 { 
    u_int16_t  sin6_family; // address family, AF_INET6 
    u_int16_t  sin6_port;  // port number, Network Byte Order 
    u_int32_t  sin6_flowinfo; // IPv6 flow information 
    struct in6_addr sin6_addr;  // IPv6 address 
    u_int32_t  sin6_scope_id; // Scope ID 
}; 

struct in6_addr { 
    unsigned char s6_addr[16]; // IPv6 address 
}; 

Jak widać, s6_addr pole 16 bajt jest już większa niż sa_data polu 14 bajtów na jego rękę. Łączny rozmiar po polu sa_family wynosi 26 bajtów.