记录一下常用的IPv4和IPv6地址格式

IPv4

IPv4地址是32位的,通常表示为“192.168.1.12”这样点分成4段的形式。
一个IP地址可以分为两部分,网络ID和主机ID。如何区分哪些位是网络ID,哪些位是主机ID,就需要子网掩码。

子网掩码

子网掩码使用来区分网段的,不同网段之间是不能直接通信的。 子网掩码的计算:ip地址与子网掩码

广播地址

主机位全为1就是该子网的广播地址。例如: 192,168.1.255/24,就是 192.168.1.0网段的广播地址。子网广播地址是可以被路由转发的,但是如"255.255.255.255"这个受限广播地址是不会被路由转发的。 参考:101-指向子网的广播

本地回环地址

127.0.0.1,数据不会经过网卡,用于本地测试

任意地址

任意地址,就是在socket编程的时候使用的 INADDR_ANY。
INADDR_ANY 实际上值得是 0.0.0.0,它的意思是不指定具体的网卡。

IPv6

IPv6地址是128位的,用:分为8个16进制的段。
ABCD:EF01:2345:6789:ABCD:EF01:2345:6789

子网掩码

与IPv4的子网掩码类似

多播地址

IPv6没有广播,只有多播。

前缀为FF00::/8的都是组播地址。

比如:FF02::1,它会发给本地链路内的所有节点,我认为他是个只能在本网段不能经过路由转发的广播。

在windows中,可以用netsh interface ipv6 show joins命令,查看机器是哪些多播组的成员

ipv6 bgp邻居 ipv6 global link_网络

本地回环地址

::1/128,用于本地测试

任意地址

任意地址,就是在socket编程的时候使用的 in6addr_any。
in6addr_any实际上值得是 0:0:0:0:0:0:0:0(即::),它的意思是不指定具体的网卡。
关于in6addr_any,发现了一篇文章,有机会验证一下:
IPv6 socket侦听in6addr_any的问题

全球单播地址和链路本地地址

IPv6的地址常用的有global 、link。
在linux中ifconfig会明确告诉,IPv6地址属于那种,例如:

inet6 addr: 2001:f80:888::159/64 Scope:Global
          inet6 addr: fe80::1fc3:1699:fe33:b227/64 Scope:Link

link地址(本地链路地址),前缀是FE80::/10 ,用于本地链路的直连通信,不能进行路由转发。
global地址,(全球唯一地址),前缀是2000::/3,用于向外通信。

->参考连接

链路本地地址和 Scope id(网卡索引)

在C++ 的socket编程中,sockaddr_in6有一个成员sin6_scope_id。

struct sockaddr_in6 {
  short sin6_family;
  u_short sin6_port;
  u_long sin6_flowinfo;
  struct in6_addr sin6_addr;
  __C89_NAMELESS union {
    u_long sin6_scope_id;
    SCOPE_ID sin6_scope_struct;
  };
};

sin6_scope_id(ULONG类型)实际上是本地网卡的索引号码。

它默认是0,相当于没有指定网卡,此时使用链路本地地址是无法进行通信的。

必须指定一个scope_id才行。

也就是下面索引这一列中的号码。

ipv6 bgp邻居 ipv6 global link_windows_02


或者我们用ipconfig命令,查看到的网卡地址中,本地连接IPv6地址后面跟了个“%20”这里就是他的网卡索引是20。

ipv6 bgp邻居 ipv6 global link_子网掩码_03

我把怎么获取Scope_id记录在本专栏的:
《[IPv6] Linux 和 Windows中如何获取sockaddr_in6的sin6_scope_id》

为什么在使用链路本地地址的时候必须要指定scope_id,而全球单播地址不需要呢?
这是因为全世界的本地链路地址都是FE80::网段的,路由没法根据网段做出区分。所以需要指定连接使用的scope id,路由才会找到目标。