IP地址的存储格式
今天看程序的时候,发现IPv4的地址以一个很奇怪的无符号整型数字存储,极其不直观。 于是觉得很奇怪,考虑这样存储的原因及改进方式。为什么不直接按照4个字节存储呢? 我考虑到的方式有两种: 1.以数组的方式存储,IPv4地址的4个字节分别是这个含有4个元素的数组的元素之一。 2.以结构体的方式存储,IPv4地址的4个字节分别是此结构体的4个1字节成员之一。 这两种方式其实是一样的。那么这就要求我们拿到的是192.168.1.108这样的IP地址, 我们通过strtok这样的函数依次取出这4个字节并存储起来。 这种做法的好处是:直观。 坏处是:需要做依次取出这4个字节的动作,并且不够通用,在某些使用需求,如IP地址查询 的时候效率低下。 后面在网上查找资料,了解到了一些信息,终于也明白为什么TCP/IP里面指明IP地址是一个 32位的无符号整数了。库函数里面有将192.168.1.108这样的IP地址转换为对应的无符号整型 数字的。 在此说下,不能直接以非3个数字位对齐的字符串方式存储IP地址,原因如下: 192168001108 ——> 192 | 168 | 001 | 108 可正确解析 1921681108 ——>具备多义性,解析出来的结果不唯一。 192.168.1.108 : 从计算机的角度来看,应该被转换二进制数字。 108 + 1 * 2 8 + 168 * 2 8 * 2 8 + 192 * 2 8 * 2 8 * 2 8 = 108 + 1 * 256 + 168 * 256 * 256 + 192 * 256 * 256 * 256 于是乎,当我们拿到一个无符号整型数字表示的IP地址的时候,可以考虑使用 库函数转换,也可以通过移位运算的方式。当然,一定要注意你获取的IP地址 的是大端还是小端的。以大端为例,数字A表示上面提到的无符号整数 (IPv4地址) ( (A & 0xff000000) >> 24 ) —— 最低字节 , 对应上面的108的位置 ( (A & 0x00ff0000) >> 16 ) —— 次低字节 , 对应上面的1的位置 ( (A & 0x0000ff00) >> 8 ) —— 次高字节 , 对应上面的168的位置 ( (A & 0x000000ff) >> 0 ) —— 最高字节 , 对应上面的192的位置 现将搜罗到的资料转载如下: IP地址的三种表示格式简析
转自: http://www.2cto.com/net/201204/127194.html
使用TCP/IP协议进行网络应用开发的朋友首先要面对的就是对IP地址信息的处理。IP地址其实有三种不同的表示格式,关于这一点,如果你还不知道,亦或对相关的知识还有所迷惑,本文对你将会有很大的帮助。
Ascii(网络点分字符串)- 网络地址(32位无符号整形,网络字节序,大头) 主机地址 (主机字节序) IP地址是IP网络中数据传输的依据,它标识了IP网络中的一个连接,一台主机可以有多个IP地址,IP分组中的IP地址在网络传输中将保持不变。下面具体介绍IP地址的三种不同表示格式。 一、点分10进制表示格式 这是我们最常见的表示格式,比如某机的IP地址可能为“202.101.105.66”。事实上,对于Ipv4(IP版本)来说,IP地址是由一个32位的二进制数所构成,但这样一串数字序列无疑是十分冗长并且 难以阅读和记忆的。为了方便人们的记忆和使用,就将这串数字序列分成4组,每组8位,并改为用 10进制数进行表示,最后用小原点隔开,于是就演变成了“点分10进制表示格式”。 来看看刚才那个IP地址的具体转化过程: IP地址:11001010011001010110100101000010 分成4组后:11001010 01100101 01101001 01000010 十进制表示:202 101 105 66 www.2cto.com 点分表示:202.101.105.66 二、网络字节顺序格式(NBO,Network Byte Order) 下面我们来谈谈网络字节顺序格式,它和我们后面将要介绍的主机字节顺序格式一样,都只在进行网络开发中才会遇到。因此,在下面的介绍中,我假设读者对Socket 编程知识有一定的基础。 在网络传输中,TCP/IP协议在保存IP地址这个32位二进制数时,协议规定采用在低位存储地址中包含数据的高位字节的存储顺序(大头),这种顺序格式就被称为网络字节顺序格式。在实际网络传输时,数据按照每32位二进制数为一组进行传输,由于存储顺序的影响,实际的字节传输顺序是由高位字节到低位字节的传输顺序。 为了使通信的双方都能够理解数据分组所携带的源地址、目的地址以及分组的长度等二进制信息,无论是主机还是 路由器,在发送每一个分组以前,都必须将二进制信息转换为TCP/IP标准的网络字节顺序格式。网络字节顺序格式的地址不受主机、路由器类型的影响,它的表示是唯一的。
在Socket编程开发中,通过函数inet_addr和inet_ntoa可以实现点分字符串与网络字节顺序格式IP地址之间的转换。 inet_addr函数原型如下: unsigned long inet_addr(const char FAR * cp) 函数中的参数cp指向网络中标准的点分地址字符串,其中每个以点分开的数字不可以大于255,这些数字可以是十进制、八进制、十六进制或者混合使用。如 “10.23.2.3”、“012.003.002.024”、“0xa.0x3.0x14.0x2”、“10.003.2.0x12”。 我们在前面的socket编程提到server端的代码,连接本地端口: /* File Name: client.c */ #include
作者 hguisu
编程中的IP地址格式总结
转自: http://blog.sina.com.cn/s/blog_4d276ac9010152jr.html 一般我们常见的网络地址格式是: 192.168.0.1,这样表示很直观,但是我们在编程使用时经常需要转换为32位无符号长整型 的网络字节序。 转换函数: int inet_aton(const char *cp,struct in_addr *inp) ; //(1) 点数格式转换成无符号长整型 char *inet_ntoa(struct in_addr in) ; //(2) 无符号长整型 转换成 点数格式 inet_addr(“a.b.c.d”); //(3)功能和(1)相同,区别是 inet_addr不支持255.255.255.255, inet_aton支持。 其中,函数里面 a 代表 ascii n 代表network.第一个函数表示将a.b.c.d的IP转换为32位的IP,存储在 inp指针里面.第二个是将32位IP转换为a.b.c.d的格式. 例子: 假设你已经有了一个sockaddr_in结构体ina,你有一个IP地址"132.241.5.10" 要储存在其中,你就要用到函数inet_addr(),将IP地址从 点数格式转换成无符号长整型。 使用方法如下:ina.sin_addr.s_addr = inet_addr("132.241.5.10"); //赋值, printf("%s",inet_ntoa(ina.sin_addr)); //显示 注意,inet_addr()返回的地址已经是网络字节格式,所以你无需再调用 函数htonl()。 注意,inet_ntoa()将结构体in-addr作为一 个参数,不是长整形。同样需要注意的是它返回的是一个指向一个字符的指针。 它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址 。 假如你需要保存这个IP地址,使用strcopy()函数来指向你自己的字符指针。 主机字节序和网络字节序说明 主机字节顺序:当一个符号用多字节表示的时候,不同的CPU在内存中可能有不同的存储顺序,这就是主机字节序。 网络字节顺序:在网络上这些顺序必须统一起来,因此有了网络字节序。 两种存储模式: 1、小端模式(LE,Little Endian) 这个符合人的思维,也比较好记,就是高地址高位,低地址低位。 2、大端模式 (BE,Big Endian) 这个符合编程习惯,因为低地址存储变量名, 低地址高位,高地址低位,那么指针按顺序输出时,高位在前低位在后,很直观。举例说明内存中双子0x01020304的存储: 地址:5001 5002 5003 5004 LE: 04 03 02 01 BE: 01 02 03 04 Intel类型的CPU采用小端对齐模式,网络字节序采用大端对齐模式。 转换函数: unsigned long int htonl(unsigned long int hostlong) unsigned short int htons(unisgned short int hostshort) unsigned long int ntohl(unsigned long int netlong) unsigned short int ntohs(unsigned short int netshort) 在这四个转换函数中,h 代表host, n 代表 network.s 代表short l 代表long 第一个函数的意义是将本机器上的long数据转化为网络上的long. 其他几个函数的意义也差不多. 参考: http://hi.baidu.com/liaimin/blog/item/1aed19d8b70ba33032fa1c45.html http://blog.csdn.net/panpengzhi/article/details/6874543 http://wenku.baidu.com/view/1f6d51fa770bf78a6529544f.html http://www.cnitblog.com/wujian-IT/archive/2007/10/11/34739. aspx
论IP地址在数据库中应该用何种形式存储
个人强烈推荐,分析细致,深入!!!!!!!!转自: http://www.cnblogs.com/skynet/archive/2011/01/09/1931044.html
在看公司项目代码时,有涉及到ip地址存储,
使用的是varbinary(4),但没有文档说明
这引发我的思考——缘起
当设计一个数据表时,考虑使用何种列的数据类型对性能有比较大的影响,如存储空间、查询开销等。甚至还影响到一些操作,如ip地址以字符串的形式存储在数据库中,就不可以直接比较大小。还有一点需要考虑,那就是可读性!数据虽然是存储在数据库中,但也要考虑到可读性问题。
本文要探讨的是“IP地址在数据库中,应该使用何种形式存储?”,文章将以实验为基础介绍使用何种形式比较适合。
1、感性认识
大家都知道ip地址分为ipv4、ipv6,这里我以ipv4为例介绍,ipv6原理是一样的。ipv4的小为32bits(或者说是4Bytes),在使用过程中,我们通常是用点分十进制格式,如192.168.120.65。如何把"192.168.120.65"存储到数据库中呢?
我们考虑下面三个因素:
- 可读性
- 存储效率
- 查询效率
把"192.168.120.65"存储到数据库中有多少中可行方法呢?见下表所示:
| 数据类型 | 大小 | 注释 |
| varchar(15) | 占7~15字节 | 可读性最好(192.168.120.65),但是最费存储空间 |
| bigint | 8 字节 | 可以将ip地址存储为类似192168120065的格式,这种可读性稍差,也比较费存储空间 |
| int | 4 字节 | 这种可读性很差,会存储为1084782657,由192*16777216+168*65536+120*256+65-2147483648计算所得,占用存储空间少。 |
| tinyint | 4 字节 | 用4个字段来分开存储ip地址,可读性稍差(分别为192, 168, 120, 65),存储空间占用少 |
| varbinary(4) | 4 字节 | 可读性差(0xC0A87841),存储空间占用少 |
从大小来看,依次varchar(15)> bigint> int、tinyint、varbinary(4)。
从可读性来看,依次是varchar(15)> bigint> tinyint> varbinary(4)>int。
从查询效率来看,
综合考虑,似乎tinyint比较好,其次是varbinary(4)。但是tinyint需要占多个表字段,而varbinary只需要占用一个字段即可。正确性还有待下面的实验检查!!!
2、理性认识
本小节通过创建5张表,分别用上述5中数据类型存储ip地址,每张表插入1,000,000条记录。说明为了方便消除差异,这些表中插入的都是192.168.120.65。建表和插入数据的sql语句如下(说明:插入1,000,000条记录要花挺长时间的,如果你要自己实验,可以考虑少插入点数据):
建表和插入数据的sql语句 然后我们执行存储过程sp_spaceused查看空间效率,执行下面的sql语句:
exec sp_spaceused ip_address_varchar
exec sp_spaceused ip_address_bigint
exec sp_spaceused ip_address_int
exec sp_spaceused ip_address_tinyint
exec sp_spaceused ip_address_varbinary
可以得到下面的结果:

说明:上面各个字段的意思如下表所示
列名
数据类型
说明
reserved
varchar(18)
由数据库中对象分配的空间总量。
data
varchar(18)
数据使用的空间总量。
index_size
varchar(18)
索引使用的空间总量。
unused
varchar(18)
为数据库中的对象保留但尚未使用的空间总量。
可以看出,这5张表中的记录都是1000000,ip_address_varchar占空间最大30792 KB;其次是ip_address_bigint和ip_address_varbinary占用16904 KB;最后是ip_address_int和ip_address_tinyint只占用16904 KB。
所以从可读性和空间效率上来看,最理想的是用tinyint的数据类型存储ip地址。其次应该考虑varbinary(4)和bigint。
理论上bigint肯定要比varbinary占用空间多,可是实验得出来是一样的,为什么呢?我查看帮助信息也没有看出什么异常,varbinary(4)的确是占用4个字节、bigint也的确是占用8个字节,如下图


如果有知道的,请告诉我一声!不过让我从这两者之间选(信不过数据结果啊),肯定会选择使用varbinary(4)而不是bigint。如果能够证明数据结果没有错,应该选择bigint,因为他的可读性更好!
3、查询效率
本小节比较上述5中存储ip地址的查询效率。为了比较查询效率,这里重新插入数据,消除每张表中的记录都相同(192.168.120.65),下面编写存储过程像数据表中随机插入1000条记录(但是保证每张表的数据是一样的)。存储过程如下:
随机插入N条ip地址到5张表中 考虑查找在范围192.0.0.0~192.255.255.255之间的ip地址的查询效率问题。说明我忽略了预处理的开销,即将192.0.0.0和192.255.255.255转换为上述的5种类型的时间,代码中我直接使用了这些值,没有给出转换过程,具体代码如下:
查询192.0.0.0~192.255.255.255之间的ip地址
执行得到的消息如下:
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
(5 行受影响)
表 'ip_address_varchar'。扫描计数 1,逻辑读取 6 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(3 行受影响)
(1 行受影响)
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 113 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
=============================共115毫秒,ip_address_varchar
(5 行受影响)
表 'ip_address_bigint'。扫描计数 1,逻辑读取 5 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(2 行受影响)
(1 行受影响)
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
===================================共4毫秒,ip_address_bigint
(5 行受影响)
表 'ip_address_int'。扫描计数 1,逻辑读取 5 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(2 行受影响)
(1 行受影响)
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 146 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
===================================共149毫秒,ip_address_int
(5 行受影响)
表 'ip_address_tinyint'。扫描计数 1,逻辑读取 5 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(2 行受影响)
(1 行受影响)
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 85 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
=======================================共88毫秒,ip_address_tinyint
(5 行受影响)
表 'ip_address_varbinary'。扫描计数 1,逻辑读取 5 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(2 行受影响)
(1 行受影响)
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 13 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
===================================共15毫秒,ip_address_varbinary
上述结果只是初略的估计了效率,可能不太精确,但还是具有一定参考价值的!我只看ip_address_varbinary(15毫秒)、ip_address_tinyint(88毫秒)、ip_address_bigint(4毫秒)。
效率差距还是挺大的,综合可读性、存储效率、查询效率,我给这三者排序是:
如果考虑存储效率,tinyint是最好的!其次是bigint,然后是varbinary(4)
如果更多的是考虑查询效率,bigint是最好的!其次是varbinary(4),然后是tinyint
如果让我选择,我会使用varbinary(4)。
转载于:https://www.cnblogs.com/sherlockhomles/archive/2013/05/24/3096547.html
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
