IP相关知识
1. IP地址
IP地址用1个32为无符号整数表示。存在 ip地址结构中
structure in_addr{
unsigned ints_addr; //网络顺序,大端法
}
备注:字节的存放顺序分:主机顺序与 网络顺序。均为无符号整数
转换函数
#include<arpa/inet.h> uint16_thtons(uint16_t hostshort); uint32_t htonl(uint32_t hostlong); uint16_t ntohs(uint16_tnetshort); uint32_t ntohl(uint32_t netlong);其中 32位的,常用于ip(4字节)转换,16 常用于 端口号(2字节) 转换。
2. IP地址表示方法
Ip地址可以 用 无符号整数表示,也可以用点分十进制表示(即字符串表示,如127.0.0.1)
(两者用途区别:个人认为 无符号整数表示 用于计算机内部处理使用;点分十进制是为了方便 程序员使用,进行输入和观察返回值时,更加直观)
转换函数
#include<arpa/inet.h>
intinet_aton(const char *string, struct in_addr*addr);
参数描述:
1 输入参数string包含ASCII表示的IP地址。
2 输出参数addr是将要用新的IP地址更新的结构。
返回值:
如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零。
char * inet_ntoa( struct in_addr in);
返回指向 点分十进制表示 的字符串
备注:其中 ‘n’ 表示 网络(network)‘a’ 表示 应用(application)
对应关系:
十六进制表示 (无符号整数) |
点分十进制表示(字符串) |
0x0 |
0.0.0.0 |
0x7f000001 |
127.0.0.1 |
0xcddea079 |
205.188.160.121 |
十六进制表示 与 点分十进制表示 字节对应关系 始终不变。因为点分十进制本来就是为了使无符号整数更加直观而设计的表示方法(个人理解)。
如0x7f000001 与127.0.0.1 127 - 7f 0 – 0 0 – 0 1– 01
示例1:编写hex2dd.c 将 十六进制 转换为 点分十进制
Unix> ./hex2dd0x8002c2f2
128.2.194.242
#include <stdio.h> #include <arpa/inet.h> int main(int ac, char *agv[]) { struct in_addr addr; unsigned int ip_h; sscanf(agv[1],"0x%x",&ip_h); unsigned int ip_n =htonl(ip_h); char *ip_s = NULL; addr.s_addr = ip_n; ip_s = inet_ntoa(addr); printf("ip_h:%x, ip_n:%x, addr_ip:%s\n",ip_h, ip_n, ip_s); return 0; }
~
示例2:编写dd2hex.c 将 点分十进制 转换为十六进制
Unix> ./dd2hex 128.2.194.242
0x8002c2f2
#include <stdio.h> #include <arpa/inet.h> int main(int ac, char *agv[]) { struct in_addr addr; unsigned int ip_h; if(inet_aton(agv[1], &addr))//success ip_h = ntohl(addr.s_addr); else printf("error"); printf("ip_h:0x%x",ip_h); return 0; }
3. IP地址与 域名 的转化
互联网中为了相互通信,为每台主机分配一个ip地址。为了更加人性化,又为其定义了域名。
如 百度 域名:www.baidu.com ip:119.75.217.56 ip:119.75.218.77
这种 域名与ip地址的映射 有DNS(域名系统) 维护。 以 主机条目结构 的形式 存储在DNS数据库中。
其中 主机条目结构类型如下
struct hostent {
char *h_name; //地址的正式名称
char **h_aliases; //空字节-地址的预备名称的指针
int h_addrtype; //地址类型; 通常是AF_INET
int h_length; //地址的比特长度
char **h_addr_list; //null-terminated array of in_addr struct
};
#define h_addr h_addr_list[0]
#include<netdb.h>
struct hostent*gethostbyname(const char * hostname);
参数为 域名,如www.baidu.com
返回:非空指针——成功,空指针——出错,同时设置h_errno
struct hostent*gethostbyaddr(const char * addr, int len, 0);
返回:非空指针——成功,空指针——出错,同时设置h_errno
参数 addr为 ip地址(无符号整数),需进行强制转换,如下, len ip地址(无符号整数)多为4个字节
struct in_addraddr;
struct hostent *myhost;
myhost =gethostbyaddr((constchar*)&addr, sizeof(addr), AF_INET);
示例:根据输入的 域名 或 ip地址(此例为 点分十进制表示法),返回 服务器主机条目结构中的信息
hostinfo.c
#include <arpa/inet.h> #include <stdio.h> #include <netdb.h> #include <stdlib.h> int main(int argc, char **argv) { char **pp; struct in_addr addr; struct hostent *hostp; if(argc != 2){ fprintf(stderr,"usage:%s, error",argv[0]); exit(0); } if(inet_aton(argv[1], &addr) != 0)//success 关键判断语句 不为0表示 将ip地址点分形式转化为 整数形式成功,说明输入的为 ip地址,而非域名 { printf("by addr\n"); hostp = gethostbyaddr((constchar*)&addr, sizeof(addr), AF_INET); } else { printf("by name\n"); hostp = gethostbyname(argv[1]); } printf("offical hostname:%s\n", hostp->h_name); for(pp = hostp->h_aliases; *pp != NULL;pp++) printf("alias:%s\n",*pp); for(pp = hostp->h_addr_list; *pp != NULL; pp++){ addr.s_addr = ((struct in_addr*)*pp)->s_addr; printf("ip:%s, 0x%x\n", inet_ntoa(addr), ntohl(addr.s_addr)); } return 0; }
测试1: ./hostinfowww.baidu.com
结果:
by name
offical hostname:www.a.shifen.com
alias:www.baidu.com
ip:119.75.217.56, 0x774bd938
ip:119.75.218.77, 0x774bda4d
测试2: ./hostinfo128.2.205.216
结果:
by addr
offical hostname:BLUEFISH.ICS.CS.CMU.EDU
ip:128.2.205.216, 0x8002cdd8