最近准备从头学习下*nix下的网络编程,参考资料为 unix网络编程 和 The Linux Programming Interface.

IPv4套接字地址结构以sockaddr_in命名,定义在<netinet/in.h>头文件中.

我的系统环境为Arch x86_64 GNU/LINUX,该结构体的定义如下

/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;         /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

其中 __SOCKADDR_COMMON 是一个定义在 <bits/sockaddr.h>中的宏

/* POSIX.1g specifies this type name for the `sa_family' member.  */
typedef unsigned short int sa_family_t;

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
   `struct sockaddr_in', `struct sockaddr_un', etc.  */

#define __SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family

所以结构体中的第一行相当于 sa_family sin_family;

前三行定义了POSIX规范中规定的:sin_family sin_addr和sin_port 三个字段.

32位的IPv4地址有两种访问方法, 假如定义了一个socket s,s.sin_addr将按in_addr结构引用其中的32位IPv4地址,而s.sin_addr.s_addr将按in_addr_t(通常是一个无符号的32位整形)引用.

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };

根据 unix网络编程 中描述,这是一个历史遗留问题,早期版本中把in_addr结构定义为多种结构的联合,允许访问一个32位IPv4地址中的所以4个字节,或访问它的两个16位值.在划分A B C类的时期,方便访问其地址中适当的字节.如今已不再需要.