linux中的网络地址结构记录

通用的地址结构sockaddr

1
2
3
4
5
6
struct  sockaddr{
     sa_family_t sa_familiy;               /* address family */
     char  sa_data[];                           /* variable-length address */
     ...
     ...
};

 实现可以自由地添加额外的成员并且定义sa_data成员的大小。

在IPV4因特网域(AF_INET)中,套接字地址用结构sockaddr_in表示:

1
2
3
4
5
6
7
8
9
struct  in_addr {
     in_addr_t s_addr;            /* IPv4 address */
};
 
struct  sockaddr_in {
     sa_family_t sin_family;           /* address family */
     in_port_t sin_port;                   /* port number */
     struct  in_addr sin_addr;          /* IPv4 address */
};

 IPv6因特网域(AF_INET6)套接字地址用如下结构sockaddr_in6表示:

1
2
3
4
5
6
7
8
9
10
11
struct  in6_addr {
     uint8_t s6_addr[16];               /* IPv6  address */
};
 
struct  sockaddr_in6 {
     sa_family_t sin6_addr[16];     /* address family */
     in_port_t sin6_port;                 /* port number */
     uint32_t sin6_flowinfo;            /* traffic class and flow info */
     struct  in6_addr sin6_addr;      /* IPv6 address */
     uint32_t sin6_scope_id;           /* set of interfaces for scope */
};

 以上是Single UNIX Specification必须的定义,每个实现可以自由的添加额外的字段。

下面考察Linux中的实现,在Linux编程时,使用sockaddr结构时,要#include <sys/socket.h>,

因此查看/urs/include/sys/socket.h内容,看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* This operating system-specific header file defines the SOCK_*, PF_*,
    AF_*, MSG_*, SOL_*, and SO_* constants, and the `struct sockaddr',
    `struct msghdr', and `struct linger' types.  */
#include <bits/socket.h>
 
#ifdef __USE_BSD
/* This is the 4.3 BSD `struct sockaddr' format, which is used as wire
    format in the grotty old 4.3 `talk' protocol.  */
struct  osockaddr
   {
     unsigned  short  int  sa_family;
     unsigned  char  sa_data[14];
   };
#endif

 对 #include <bits/socket.h>的注释中说了,sturct sockaddr实际上是定义在bits/socket.h中的

(后面的osockaddr结构是4.3BSD中的sockaddr结构,可以看出SUS规定的和该结构完全一致,

实际上,UNIX和Linux上的socket实现都是从BSD的socket实现演变过来的。)

我们再查看bit/socket.h的内容,找到

1
2
3
4
5
6
7
8
9
/* Get the definition of the macro to define the common sockaddr members.  */
#include <bits/sockaddr.h>
 
/* Structure describing a generic socket address.  */
struct  sockaddr
   {
     __SOCKADDR_COMMON (sa_);     /* Common data: address family and length.  */
     char  sa_data[14];        /* Address data.  */
   };

 其中出现了一个宏__SOCKADDR_COMMON(),根据第1、2行到文件/usr/include/bits/sockaddr.h

中去查找该宏,得到

1
2
3
4
5
6
7
8
9
/* 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_t类型,该类型在linux中就是无符号短整型,用来表示地址类型;

第八行定义了__SOCKADDR_COMMON(sa_prefix)宏,其中出现了预定义宏##,该预定义宏的

作用见另一篇博文();

宏__SOCKADDR_COMMON(sa_prefix)定义了一个以sa_prefix和family合并起来为变量名的

变量,该变量类型为sa_family_t。

宏__SOCKADDR_COMMON(sa_prefix)展开得到

1
sa_family_t sa_familiy;

 和SUS要求的一致。

在考察linux中的sockaddr_in和sockadd_in6,使用这两个结构,应该#include <netinet/in.h>

(apra/inet.h包含了netinet/in.h,使用#include <apra/inet.h>的话就不用包含后者了。)

于是在/usr/include/netinet/in.h中查到到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 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)];
   };
 
/* Ditto, for IPv6.  */
struct  sockaddr_in6
   {
     __SOCKADDR_COMMON (sin6_);
     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 */
   };

 其中sockaddr_in6和SUS要求的完全一样,sockaddr_in多了一个成员

该成员中有一个宏定义__SOCKADDR_COMMON_SIZE,从字面意思看应该时__SOCKADDR_COMMON

的大小,而前面看到宏__SOCKADDR_COMMON()实际上定义了一个sa_family_t类型(在linux中实现

为无符号短整形)的变量

前面在/usr/include/bits/sockaddr.h中看到该宏定义如下:

1
#define __SOCKADDR_COMMON_SIZE  (sizeof (unsigned short int))

 验证了上述猜测。

多出的一个成员起填充字段的作用,为了将sockaddr_in结构补全至和sockaddr结构的大小一致。

这样,sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向

sockaddr的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,

然后用进行类型转换就可以了。

1
2
3
struct  sockaddr_in *sinp;
/* ai_addr为从某个函数返回sockaddr结构的指针 */
sinp = ( struct  sockaddr_in *)ai_addr;

 在看看linux中的in_addr和in6_addr结构,在/usr/include/netinet/in.h中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Internet address.  */
typedef  uint32_t in_addr_t;
struct  in_addr
   {
     in_addr_t s_addr;
   };
...
...
/* IPv6 address */
struct  in6_addr
   {
     union
       {
     uint8_t __u6_addr8[16];
#if defined __USE_MISC || defined __USE_GNU
     uint16_t __u6_addr16[8];
     uint32_t __u6_addr32[4];
#endif
       } __in6_u;
#define s6_addr         __in6_u.__u6_addr8
#if defined __USE_MISC || defined __USE_GNU
# define s6_addr16      __in6_u.__u6_addr16
# define s6_addr32      __in6_u.__u6_addr32
#endif
   };

 ipv6地址结构中用到了共用体,其中三个变量都占128位(都是同一个IPv6地址,只是访问字节数不一样)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值