preface
Students who have read UNIX network programming know that this book introduces all aspects of sockets in detail, and gives each structure
Implementation code file of system API. However, with the continuous development of technology, the kernel of the operating system is constantly updated. The book describes the relevant address structures, and
The specific implementation source files sometimes do not match.
In view of this, based on the description in the book, this paper takes relevant notes in combination with the linux operating system, which is used for reading and easy to find.
Dependency:
- Book UNIX network programming (Volume I) version 3
- Operating system platform: Centos8 [Linux Centos 3.10.0-1160.49.1.el7.x86_64]
If specified, the content of this article is based on this operating system platform.
Notes:
IPv4 socket address structure:
sokcaddr_in, definition file: / usr / include / netinet / in h
29 /* Internet address. */ 30 typedef uint32_t in_addr_t; 31 struct in_addr 32 { 33 in_addr_t s_addr; 34 }; 237 /* Structure describing an Internet socket address. */ 238 struct sockaddr_in 239 { 240 __SOCKADDR_COMMON (sin_); 241 in_port_t sin_port; /* Port number. */ 242 struct in_addr sin_addr; /* Internet address. */ 243 244 /* Pad to size of `struct sockaddr'. */ 245 unsigned char sin_zero[sizeof (struct sockaddr) 246 - __SOCKADDR_COMMON_SIZE 247 - sizeof (in_port_t) 248 - sizeof (struct in_addr)]; 249 };
__ SOCKADDR_COMMON and__ SOCKADDR_COMMON_SIZE is a macro definition,
Its definition file: / usr / include / bits / SOCKADDR h.
34 #define __SOCKADDR_COMMON(sa_prefix) \ 35 sa_family_t sa_prefix##family 36 37 #define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))
So actually sokcaddr_in structure is defined as follows:
struct sokcaddr_in { sa_family_t sin_family; int_port_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[sizeof (struct sockaddr) - (sizeof (unsigned short int)) - sizeof (in_port_t) - sizeof (struct in_addr)]; };
sa_family_t is defined in: / usr / include / bits / SOCKADDR h:
27 /* POSIX.1g specifies this type name for the `sa_family' member. */ 28 typedef unsigned short int sa_family_t;
An unsigned short integer with a length of 16 bits.
in_port_t is defined in: / usr / include / netinet / in h.
118 /* Type to represent a port. */ 119 typedef uint16_t in_port_t;
Unsigned 16 bit integer representing the port number. Under IPv4, the port number is always saved in network byte order.
Universal socket address structure:
The emergence of general socket is to meet that the socket function can handle the socket structure address from any supported protocol family. For C language
For example, a direct void * pointer is enough, but ANSI C did not appear when sockets appeared (sockets first appeared in 1982),
Therefore, the designer defines a general address structure struct sockaddr. Currently, the structure is defined in:
/usr/include/bits/socket.h.
177 /* Structure describing a generic socket address. */ 178 struct sockaddr 179 { 180 __SOCKADDR_COMMON (sa_); /* Common data: address family and length. */ 181 char sa_data[14]; /* Address data. */ 182 };
Expand macro__ SOCKADDR_COMMON definition, and finally struct sockaddr is defined as follows:
struct sockaddr { sa_family_t sa_family; char sa_data[14]; }
Therefore, socket is defined as taking a pointer to a general socket address structure as one of its parameters. This requires calls to these functions
The pointer of the address structure specifying a specific protocol needs to be cast into a pointer to a general socket address structure to adapt to
Function parameter requirements.
IPv6 socket address structure
The socket address structure of IPv6 protocol is: struct sockaddr_in6,
Defined in: / usr / include / netinet / in h.
211 /* IPv6 address */ 212 struct in6_addr 213 { 214 union 215 { 216 uint8_t __u6_addr8[16]; 217 uint16_t __u6_addr16[8]; 218 uint32_t __u6_addr32[4]; 219 } __in6_u; 220 #define s6_addr __in6_u.__u6_addr8 221 #ifdef __USE_MISC 222 # define s6_addr16 __in6_u.__u6_addr16 223 # define s6_addr32 __in6_u.__u6_addr32 224 #endif 225 }; 253 struct sockaddr_in6 254 { 255 __SOCKADDR_COMMON (sin6_); 256 in_port_t sin6_port; /* Transport layer port # */ 257 uint32_t sin6_flowinfo; /* IPv6 flow information */ 258 struct in6_addr sin6_addr; /* IPv6 address */ 259 uint32_t sin6_scope_id; /* IPv6 scope-id */ 260 };
The actual definitions after macro expansion are as follows:
struct sockaddr_in6 { sa_family_t sin6_family; in_port_t sin6_port; /* Transport layer port # */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* IPv6 scope-id */ };
New universal socket structure
struct sockaddr_ The storage structure overcomes the shortcomings of the old struct SOCKADDR general socket structure.
The new structure is sufficient to accommodate any socket address structure supported by the system.
It is defined in the header file: / usr / include / bits / socket h.
185 /* Structure large enough to hold any socket address (with the historical 186 exception of AF_UNIX). */ 187 #define __ss_aligntype unsigned long int 188 #define _SS_PADSIZE \ 189 (_SS_SIZE - __SOCKADDR_COMMON_SIZE - sizeof (__ss_aligntype)) 190 191 struct sockaddr_storage 192 { 193 __SOCKADDR_COMMON (ss_); /* Address family, etc. */ 194 char __ss_padding[_SS_PADSIZE]; 195 __ss_aligntype __ss_align; /* Force desired alignment. */ 196 };
__ SS_SIZE and__ SOCKADDR_COMMON_SIZE. Are defined in: / usr / include / bits / SOCKADDR h
#define __SS_SIZE 128 #define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))
Therefore, after macro expansion, the structure is defined as follows:
struct sockaddr_storage { sa_family ss_family; char __ss_padding[128-sizeof(unsigned short int)-sizeof(unsigned long int)]; unsigned long int __ss_align; }
[Abstract] sockaddr_ There are two differences between the general socket address structure provided by storage type and sockaddr.
- 1. If any socket address structure supported by the system needs alignment, sockaddr_storage can meet the most demanding alignment requirements.
- 2,sockaddr_storage is the largest enough to accommodate any socket address structure supported by the system.
Note: except SS_ Other fields of family are transparent to users. sockage_ The structure must be converted to storage or forced to copy
Suitable for SS_ Other fields can only be accessed in the socket address structure of the address type given by the family field.