我们在进行网络编程时,绝大部分情况都会涉及到 IP 协议,因此了解一下 IP 协议是很有必要的。不过由于 IP 协议本身不算简单,而我们更多的是使用 TCP/UDP 等上层协议进行网络编程,因此要必要了解一下 IP 地址。
IP 地址的组织形式
IP 地址的表示
IP 地址实际上是 32 bit 的数字(也就是4字节),不过由于二进制的可读性太差,所以计算机网络沿用了信息技术中的表示法,将 IP 地址按 8 bit 分成4组,每组用一个十进制数字来表示,数字之间用点做分隔,也就是所谓的点分十进制。
比如,从上图可以看出 IP 地址
172.16.254.1
对应于二进制 10101100 00010000 11111110 00000001
。
因为计算机只能识别二进制,所以编程时需要将点分十进制转换成计算机可识别的二进制,这也就是为什么 Linux/Unix 需要
inet_aton
inet_addr
inet_ntoa
这三个函数进行 IP 地址的转换。五类 IP 地址
虽说 IP 地址实际上是二进制数字,但它并不是像
0.0.0.0
、0.0.0.1
、0.0.0.2
... 这样构造的,而是被划分为 ABCDE 五类。那么为什么要划分呢?主要是为了分配、识别和管理的方便1。比如:你看到 3.xxx.xxx.xxx
马上就能知道,这是 A 类地址,拥有这个地址的肯定是个大型机构(类似 省.市.区.家
)。类别 | 范围 | 说明 |
---|---|---|
A 类 | 0.0.0.0 - 127.255.255.255 | 用于规模非常大的网络,比如国家或者大公司 |
B 类 | 128.0.0.0 - 191.255.255.255 | 用于中等规模的网络,比如学校 |
C 类 | 192.0.0.0 - 223.255.255.255 | 通常用于小企业 |
D 类 | 224.0.0.0 - 239.255.255.255 | 用于多播 |
E 类 | 240.0.0.0 - 255.255.255.255 | 实验用2 |
根据接收端的数量,IP 地址又可以分成三种:unicast(特定主机)、broadcast(所有局域网中的主机)或multicast(一组主机)。
网段与子网掩码
因为广播和路由3的存在,需要将 IP 地址划分成不同的网段(试想全地球的人都呆在一个大房子里面会是多么不方便?),例如:ABC 类中的网络 ID 就指明了 IP 所在的网段。有时候为了联机玩魔兽方便的处理多个主机,我们需要将它们放到一个网段下,而且希望能够与其他主机隔离,这时候就可以通过设置子网掩码将固定网段进一步划分。
比如:C 类地址
192.168.137.1
,子网掩码 255.255.255.240
就表示它位于 192.168.137.0 - 192.168.137.15
网段内,也就是同一个局域网下。
子网掩码长得很像 IP 地址,它实际上也是二进制数字,例如:
255.255.255.240
对应 11111111 11111111 11111111 11110000
。计算机最擅长做的是什么?二进制的运算。所以判断 IP 地址是不是位于某个网段是通过将 IP 地址与子网掩码做逻辑与来判断的。4
子网掩码可以是任意的 32 bits 数字,但是实际中无一例外是以全1开头全0结束。
相比使用 IP 地址和子网掩码表示网段,CIDR(Classless Inter-Domain Routing)表示法更为方便,可读性也更高。前面的例子用 CIDR 表示为
192.168.137.0/28
。CIDR 表示法由三部分组成:IP 地址、斜杠、掩码前缀1的个数。网段的计算方法和子网掩码方式等价,除了斜杠后的数字表示子网掩码1开头的位数以外,并无区别。看下面这个例子就明白了。192.168.100.0/22 |
---|
11000000 10101000 01100100 00000000 |
11111111 11111111 11111100 00000000 |
192.168.100.0 - 192.168.103.255 |
特殊的 IP 地址
有些特殊的 IP 地址5我们在编程时经常遇到,这里列个表总结一下。
CIDR地址块 | 说明 |
---|---|
0.0.0.06 | 本机的所有 IP 地址 |
127.0.0.0/8 | 环回地址 |
10.0.0.0/8 | 局域网 |
172.16.0.0/12 | 局域网 |
192.168.0.0/16 | 局域网 |
224.0.0.1 | 子网所有设备 |
255.255.255.255 | 广播地址 |
子网最后一个地址 | 广播地址 |
子网的第一个地址 | 网络识别码,代表整个子网,不能被分配 |
本机 IP
127.0.0.1
假设你需要写一个服务器。我们知道,监听套接字的时候得绑定一个 IP 地址,要不然客户端就不知道跟谁通信了。假设你在宿舍调试到一半要去上课,于是抱着电脑跑到教学楼,连上 WiFi,查看获取到的 IP ,再更改代码或者配置里面的 IP 地址,然后继续调试,下课回到寝室又得重复这个步骤...
环回地址解决了这个问题。它表示本机地址,发往环回地址的报文都不会出现在网络中(主机之外),而是被直接送到入口队列中(如果抓包不到,可能是这个原因)。所以
127.0.0.1
经常被用于调试或本机进程间通信。0.0.0.0
回到前面那个例子,虽然将套接字绑定在
127.0.0.1
上能避免更换网络环境时改 IP 的麻烦,但是其他机器就访问不了服务器了。为了既能避免改 IP 的麻烦,又能让其他机器连接上来,我们可以将套接字绑定在 0.0.0.0
上。0.0.0.0
代表了本机上所有的 IP 地址,什么意思呢?当你输入 ifconfig
命令的时候,你会看到一堆的 IP,包括:每个网卡的 IP、虚拟机的 IP、环回接口的 IP...而 0.0.0.0
就像黑洞,吞下了所有发往这些 IP 的数据。你从局域网访问服务器,它就是局域网的 IP,从本机访问它就是 127.0.0.1
...局域网地址
10.0.0.0 - 10.255.255.255
、172.16.0.0 - 172.31.255.255
、192.168.0.0 - 192.168.255.255
表示局域网 IP。位于局域网中的主机不能直接与公共网络通信,这些 IP 地址在局域网外也不能路由。但通过 NAT 可以做到前者。
如果你的服务器别人访问不了,检查一下 IP 地址是不是位于局域网中(也有可能是被网络管理员限制了)。
广播地址
如果你不知道什么是广播,分别
ping
一下 224.0.0.1
、255.255.255.255
、子网最后一个 IP
看看会发生什么。参考文献
- Wiki: Dot-decimal notation
- IP address
- Why are IP addresses divided into classes
- IPv4 exhaustion what about class E addresses
- 协议森林03 IP接力赛 (IP, ARP, RIP和BGP协议)
- Wiki: Classless Inter-Domain Routing
- Wiki: IPv4
IPv4 出现地址耗尽危机后有人提议使用 E 类地址,但是由于有些操作系统和路由器不支持 E 类地址,所以这部分地址并不能在实际中使用。
因为路由器需要使用路由表保存所在网段的路由信息,而路由器的硬件资源有限只能保存部分路由信息,如果网段主机太多会导致路由表更新频繁,从而致使网络质量下降,所以需要划分网段。
这里有些习题帮你巩固子网掩码的概念。
Wiki 上有更完整的特殊 IP 地址的列表。
No comments:
Post a Comment