IP 地址是由小数点分开的十进制数表示的,我们称之为点分十进制表示法。
Internet 地址分类
一个 Internet 地址是由 网络地址 和 主机地址 构成的。
IP 地址占 32 位,但是 网络地址 和 主机地址 之间的界限并不是固定的,而界限的确定取决于地址的分类,下表总结了 IP 地址分类的方法:
理解网络掩码:
网络掩码的作用在于把网络地址从 IP 地址从提取出来,实际上代表网络掩码的 IP 号和某一特定的 IP 地址进行“按位与”操作。
如果我们需要建立自己的 IP 网络,那么就必须确定网络掩码,如下图:
软件有时候需要提供将 IP 地址进行分类的能力,下面的例子就展示了这个操作:
---------UNDONE(此处代码待添加)
分配 IP 地址
IP 地址是通过 InterNIC 分配给不同的组织和个人的。但是并非所有的 IP 地址都可以用来分配,其中也有一些私有的,或者说是预留出来的。
私有 IP
一般 IP 地址都需要在 InterNIC 进行登记,但是如果你的系统没有直接连接到 Internet,那么久不需要全球唯一的地址,这个时候就可以使用私有 IP 地址来替代。
RFC1597 就是描述怎么分配私有 IP 地址的文档。
最后到底选择哪一种 IP 地址在很大的程度上取决于所需要建立的网络数量,分离的网段以及每个网段上主机的数目。
保留 IP 地址
保留 IP 地址的数量很多,在 RFC1166 文档中有记录。下面就是一个保留 IP 地址的实例:
操作 IP 地址
inet_addr()函数的语法如下:
1
2
3
4
5
6
|
#include <sys/socket.h>
#include <neiinet/in.h>
#include <arpa/inet.h>
unsigned
long
inet_addr(
const
char
* string);
|
这个函数使用 string 作为输入参数,并将这个点分十进制的 IP 地址转换为 32 位的二进制表示法,函数的返回值就是这个 32 位的二进制的网络字节序。当然如果 string 不是一个有效的点分十进制 IP 地址,函数返回 INADDR_NONE。另外需要注意的是,当 inet_addr 函数返回 INADDR_NONE 的时候,它并没有建立一个有效的 errno 值,所以当函数返回错误的时候,不要去测试 errno 的值。
注意:
在新程序中避免使用 inet_addr 函数,而应该使用 inet_aton 函数作为代替。因为对于 inet_addr 函数来说,即使输入的参数是有效的 IP 地址:255.255.255.255,他的返回值仍然是 INADDR_NONE。
下面我们来说说 inet_aton 函数:
inet_aton() 函数是将字符串形式的 IP 地址转换为网络字节序的 32 位 IP 地址的改进形式。语法如下:
1
2
3
4
5
|
#include <sys/socket.h>
#include <neiinet/in.h>
#include <arpa/inet.h>
int
inet_aton(
const
char
* string,
struct
in_addr*addr);
|
参数 string 表示点分十进制 IP 地址的 ASCII 表示。输出参数 addr 是一个被新的 IP 地址跟新的结构。函数调用成功返回非 0 值。失败返回 0。当然它也没有建立一个有效的 errno 值。
下面我们来看看inet_ntoa() 函数
有时候当用户连接到你的服务器的时候,需要知道他的 IP 地址,系统提供了 inet_ntoa 函数将 32 位的二进制 IP 地址表示转换为点分十进制的字符串形式:
1
2
3
4
5
|
#include <sys/socket.h>
#include <neiinet/in.h>
#include <arpa/inet.h>
char
* inet_ntoa(
struct
in_addr addr);
|
需要注意的是inet_ntoa 函数的返回值直到下次调用前一直有效。所以如果在线程中使用 inet_ntoa 的时候,一定要确保每次只有一个线程调用本函数。否则一个线程的返回的结构可能被其他线程返回的结果所覆盖。
接下来我们来看看inet_network() 函数。
当我们需要用网络掩码将 IP 地址中的网络位或者主机位提取出来的时候,如果能将点分十进制的 IP 地址转换为主机字节序的 32 位二进制 IP 地址形式就方便了,而 inet_network 函数的作用就是如此、语法如下:
1
2
3
4
5
|
#include <sys/socket.h>
#include <neiinet/in.h>
#include <arpa/inet.h>
unsigned
long
inet_network(
const
char
* addr);
|
函数的输入参数是存储在字符串 addr 中的点分十进制 IP 地址,返回值是主机字节序的 32 位二进制地址,但是如果输入参数不正确,返回值是 0xFFFFFFFF.
以主机字节序的形式返回结果可以保证用户安全的使用网络掩码,因为如果返回值是网络字节序的话,那么不同的 CPU 平台所使用的网络掩码和程序代码就会有差异。
我们来看看inet_lnaof() 函数。
函数 inet_lnaof 函数是将套接口地址中的 IP 地址(网络字节序)转换为没有网络位的主机 ID(主机字节序),这个函数为我们省去了很多的麻烦,因为我们不需要对 IP 地址进行分类,再将主机位从 IP 地址中提取出来。函数语法如下:
简言之,IP 地址由 网络地址 和 主机地址 组成,该函数可以去掉 IP 地址中的网络地址,只保留主机地址。
1
2
3
4
5
|
#include <sys/socket.h>
#include <neiinet/in.h>
#include <arpa/inet.h>
unsigned
long
inet_lnaof(
struct
in_addr addr);
|
下面的表提供了一些可以作为inet_lnaof函数输入的典型例子和返回值:
我们再来看看inet_netof() 函数
inet_lnaof 函数返回的是主机 ID,而 inet_netof 函数返回的是网络 ID,函数语法如下:
去掉 IP 地址中的主机地址,只保留网络地址,所以函数名为 net of,反倒是 lna of 不好记忆
1
2
3
4
5
|
#include <sys/socket.h>
#include <neiinet/in.h>
#include <arpa/inet.h>
unsigned
long
inet_netof(
struct
in_addr addr);
|
下表展示了一些例子:
然后我们再来看看inet_makeaddr() 函数吧。根据之前的内容我们知道使用 inet_netof 函数和 inet_lnaof 函数,我们就可以把 IP 地址中的主机为和网络位分别提取出来,有时候我们还需要根据提取出来的主机位和网络为合并为一个新的 IP 地址。这个时候我们就可以使用 inet_makeaddr 函数。
1
2
3
4
5
|
#include <sys/socket.h>
#include <neiinet/in.h>
#include <arpa/inet.h>
struct
in_addr inet_makeaddr(
int
net ,
int
host);
|