Linux环境下网络编程杂谈
2016-07-24 10:58
513 查看
今天我们说说“Pre-网络编程”。内容比较杂,但都是在做网络应用程序开发过程中经常要遇到的问题。
一、大端、小端和网络字节序
小端字节序:little-endian,将低字节存放在内存的起始地址;
大端字节序:big-endian,将高字节存放在内存的其实地址。
例如,数字index=0x11223344,在大小端字节序方式下其存储形式为:
![](/attachment/201207/11/23069658_1342018314FjfB.jpg)
上图一目了然的可以看出大小端字节序的区别。
还有另外一个概念就是网络字节序。网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian方式。注意:X86系列CPU都是小端little-endian字节序,即低字节存低位,高字节存高位。
为此,Linux专门提供了字节转换函数.
在这四个转换函数中,h代表host,n代表 network,s代表short,l代表long 。htonl()函数的意义是将本机器上的long数据转化为网络上的long。其他几个函数的意义也差不多。
看个例子:
![](/attachment/201207/11/23069658_1342018343OpO1.jpg)
也就是说对于从网络上接收到的非单子节的基本数据类型数据,首先需要用ntohl(s)将其转换成本地字节序;同理,发往网络的非单子节的基本数据类型数据,首先用htonl(s)将其转换成网络字节序。这里最常见的就是IP地址和端口号。
二、点分十进制格式的IP地址和32bit的IP地址
我们常见的IP地址都是以点分十进制格式表示,例如“172.18.1.231”。而在程序中基本是以如下的结构表示一个IP:
它和点分十进制格式的IP地址可以通过一组API实现相互转换:
这两个函数所要求的struct
in_addr{}参数均为网络字节序。
继续看例子:
![](/attachment/201207/11/23069658_1342018355TTWR.jpg)
“192.168.11.23”转换成数字就是0xc0a80b17,是网络字节序的。如果直接打印,那么本地按照小端字节序来输出,结果为net addr = 170ba8c0,刚好和实际相反。当我们先将其转换成本地字节序,然后再输出时结果就OK了,即host addr = c0a80b17。同理,inet_ntoa()也类似。
三、网络主机名和IP地址的对应关系
在做网络编程时经常要碰到的一个问题就是根据对方主机名来获取其IP地址,或者根据IP地址反过来解析主机名和其他信息。Linux提供了两个常用的API:
这两个函数失败时返回NULL且设置h_errno错误变量,调用hstrerror(h_errno)或者herror("Error");可以得到详细的出错信息。成功时均返回如下结构:
gethostbyname可以将机器名(如www.google.com)转换为一个结构指针,gethostbyaddr可以将一个32位的IP地址(C0A80001)转换为结构指针。对于gethostbyaddr函数来说,输入参数“addr”的类型根据参数“type”来确定,目前type仅取AF_INET或AF_INET6。例如,type=2(即AF_INET),则addr就必须为struct in_addr{}类型。 继续看例子:
运行结果如下:
![](/attachment/201207/11/23069658_1342018366AM0i.jpg)
当我们调用gethostbyaddr根据CU主页的IP地址获取其站点信息时返回的错误是“未知的主机”错误,原因留给大家自己思考吧。这充分说明对了于gethostbyname()函数和gethostbyaddr()函数的调用一定要判断其返回值。
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(16366) | 评论(8) | 转发(43) |
2
上一篇:SNMP从入门到开发:进阶篇
下一篇:Linux网络编程:基于TCP的程序开发回顾篇
相关热门文章
linux下网络程序遭遇SIGPIPE的...
Linux网络编程:原始套接字的...
Linux网络编程之使用TCP传输文...
linux下网络程序遭遇SIGPIPE的...
交叉编译faad
linux 常见服务端口
xmanager 2.0 for linux配置
【ROOTFS搭建】busybox的httpd...
openwrt中luci学习笔记
什么是shell
linux dhcp peizhi roc
关于Unix文件的软链接
求教这个命令什么意思,我是新...
sed -e "/grep/d" 是什么意思...
谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
![](http://passport.ixpub.net/data/avatar/031/13/93/75_avatar_small.jpg)
王茂春2016-05-05 22:30:24
wj20095356:我觉得博主第二个关于字节序的例子解释有误,我认识是这样的,192.168.11.23在内存里面存放的顺序按地址由低到高本来就是192 168 11 23,只是printf输出一个数字的时候先显示高位后显示低位。
确实,我在这个地方看了很久,博主把这个概念讲复杂和混淆了,addr.s_addr是网络字节顺序的,别的不需要考虑太多回复 | 举报
![](http://passport.ixpub.net/data/avatar/028/77/75/14_avatar_small.jpg)
wj200953562015-02-11 20:03:03
我觉得博主第二个关于字节序的例子解释有误,我认识是这样的,192.168.11.23在内存里面存放的顺序按地址由低到高本来就是192 168 11 23,只是printf输出一个数字的时候先显示高位后显示低位。
回复 | 举报
![](http://passport.ixpub.net/data/avatar/029/10/29/94_avatar_small.jpg)
ruanben2014-07-02 21:07:37
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
回复 | 举报
![](http://passport.ixpub.net/data/avatar/029/60/40/68_avatar_small.jpg)
xingfengshi2014-04-13 21:14:25
fanxiao_cn:大神, 为什么“printf("IP = %x.%x.%x.%x\n", *(c)&0xff, *(c+1)&0xff, *(c+2), *(c+3));”里面*c和*(c+1)要&0xff, 我试了不与的话像*c返回值会成为0xffffffc0, 为什么呢? 第一个例子中的0x11223344 为什么就不需要与0xff?
同问啊~~~!!!~!·!回复 | 举报
![](http://passport.ixpub.net/data/avatar/029/60/40/68_avatar_small.jpg)
xingfengshi2014-04-12 23:16:39
写得很不错,对于一些问题的理解很有帮助哦
回复 | 举报
首页
上一页
1
2
下一页
末页
评论热议
一、大端、小端和网络字节序
小端字节序:little-endian,将低字节存放在内存的起始地址;
大端字节序:big-endian,将高字节存放在内存的其实地址。
例如,数字index=0x11223344,在大小端字节序方式下其存储形式为:
![](/attachment/201207/11/23069658_1342018314FjfB.jpg)
上图一目了然的可以看出大小端字节序的区别。
还有另外一个概念就是网络字节序。网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian方式。注意:X86系列CPU都是小端little-endian字节序,即低字节存低位,高字节存高位。
为此,Linux专门提供了字节转换函数.
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) |
看个例子:
![](/attachment/201207/11/23069658_1342018343OpO1.jpg)
也就是说对于从网络上接收到的非单子节的基本数据类型数据,首先需要用ntohl(s)将其转换成本地字节序;同理,发往网络的非单子节的基本数据类型数据,首先用htonl(s)将其转换成网络字节序。这里最常见的就是IP地址和端口号。
二、点分十进制格式的IP地址和32bit的IP地址
我们常见的IP地址都是以点分十进制格式表示,例如“172.18.1.231”。而在程序中基本是以如下的结构表示一个IP:
struct in_addr { __be32 s_addr; //其实就是一个32bit的数字 }; |
int inet_aton(const char *cp,struct in_addr *inp) 无效的地址cp则返回0;否则返回非0 char *inet_ntoa(struct in_addr in) 将一个32位的IP地址转换成点分十进制字符串。 |
in_addr{}参数均为网络字节序。
继续看例子:
![](/attachment/201207/11/23069658_1342018355TTWR.jpg)
“192.168.11.23”转换成数字就是0xc0a80b17,是网络字节序的。如果直接打印,那么本地按照小端字节序来输出,结果为net addr = 170ba8c0,刚好和实际相反。当我们先将其转换成本地字节序,然后再输出时结果就OK了,即host addr = c0a80b17。同理,inet_ntoa()也类似。
三、网络主机名和IP地址的对应关系
在做网络编程时经常要碰到的一个问题就是根据对方主机名来获取其IP地址,或者根据IP地址反过来解析主机名和其他信息。Linux提供了两个常用的API:
struct hostent *gethostbyname(const char *name); struct hostent *gethostbyaddr(const void *addr, int len, int type); |
struct hostent { char *h_name; /* 主机名*/ char **h_aliases; /* 主机别名的列表*/ int h_addrtype; /* 地址类型,AF_INET或其他*/ int h_length; /* 所占的字节数,IPv4地址都是4字节 */ char **h_addr_list; /* IP地址列表,网络字节序*/ } #define h_addr h_addr_list[0] /*后向兼容 */ |
#include #include #include #include #include #include #include int main(int arg,char** argv){ struct hostent *host,*host2; if(NULL == (host = gethostbyname(argv[1]))){ herror("Error"); return 1; } printf("name = %s\n",host->h_name); printf("aliases = %s\n",*host->h_aliases); printf("add type = %d\n",host->h_addrtype); printf("len = %d\n",host->h_length); printf("IP=%s\n",inet_ntoa(*(struct in_addr*)host->h_addr)); printf("=================================\n"); struct in_addr maddr; if(0 == inet_aton(argv[2],&maddr)){ return 0; } char* c = (char*)&maddr; printf("org = %x.%x.%x.%x\n",*(c)&0xff,*(c+1)&0xff,*(c+2)&0xff,*(c+3)&0xff); if(NULL == (host2 = gethostbyaddr(&maddr,4,2))){ printf("Error:%s\n",hstrerror(h_errno)); return 1; } printf("name = %s\n",host2->h_name); printf("aliases = %s\n",*host2->h_aliases); printf("add type = %d\n",host2->h_addrtype); printf("len = %d\n",host2->h_length); printf("IP=%s\n",inet_ntoa(*(struct in_addr*)host2->h_addr)); return 0; } |
![](/attachment/201207/11/23069658_1342018366AM0i.jpg)
当我们调用gethostbyaddr根据CU主页的IP地址获取其站点信息时返回的错误是“未知的主机”错误,原因留给大家自己思考吧。这充分说明对了于gethostbyname()函数和gethostbyaddr()函数的调用一定要判断其返回值。
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(16366) | 评论(8) | 转发(43) |
2
上一篇:SNMP从入门到开发:进阶篇
下一篇:Linux网络编程:基于TCP的程序开发回顾篇
相关热门文章
linux下网络程序遭遇SIGPIPE的...
Linux网络编程:原始套接字的...
Linux网络编程之使用TCP传输文...
linux下网络程序遭遇SIGPIPE的...
交叉编译faad
linux 常见服务端口
xmanager 2.0 for linux配置
【ROOTFS搭建】busybox的httpd...
openwrt中luci学习笔记
什么是shell
linux dhcp peizhi roc
关于Unix文件的软链接
求教这个命令什么意思,我是新...
sed -e "/grep/d" 是什么意思...
谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
![](http://passport.ixpub.net/data/avatar/031/13/93/75_avatar_small.jpg)
王茂春2016-05-05 22:30:24
wj20095356:我觉得博主第二个关于字节序的例子解释有误,我认识是这样的,192.168.11.23在内存里面存放的顺序按地址由低到高本来就是192 168 11 23,只是printf输出一个数字的时候先显示高位后显示低位。
确实,我在这个地方看了很久,博主把这个概念讲复杂和混淆了,addr.s_addr是网络字节顺序的,别的不需要考虑太多回复 | 举报
![](http://passport.ixpub.net/data/avatar/028/77/75/14_avatar_small.jpg)
wj200953562015-02-11 20:03:03
我觉得博主第二个关于字节序的例子解释有误,我认识是这样的,192.168.11.23在内存里面存放的顺序按地址由低到高本来就是192 168 11 23,只是printf输出一个数字的时候先显示高位后显示低位。
回复 | 举报
![](http://passport.ixpub.net/data/avatar/029/10/29/94_avatar_small.jpg)
ruanben2014-07-02 21:07:37
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
回复 | 举报
![](http://passport.ixpub.net/data/avatar/029/60/40/68_avatar_small.jpg)
xingfengshi2014-04-13 21:14:25
fanxiao_cn:大神, 为什么“printf("IP = %x.%x.%x.%x\n", *(c)&0xff, *(c+1)&0xff, *(c+2), *(c+3));”里面*c和*(c+1)要&0xff, 我试了不与的话像*c返回值会成为0xffffffc0, 为什么呢? 第一个例子中的0x11223344 为什么就不需要与0xff?
同问啊~~~!!!~!·!回复 | 举报
![](http://passport.ixpub.net/data/avatar/029/60/40/68_avatar_small.jpg)
xingfengshi2014-04-12 23:16:39
写得很不错,对于一些问题的理解很有帮助哦
回复 | 举报
首页
上一页
1
2
下一页
末页
评论热议
相关文章推荐
- (十)洞悉linux下的Netfilter&iptables:网络地址转换原理之SNAT
- (九)洞悉linux下的Netfilter&iptables:网络地址转换原理之DNAT
- Linux 网络协议栈纲要
- linux内核ipv4网络部分分层结构及涉入源文件
- linux 内核网络,数据接收流程图
- (五)httpd-2.4的编译安装(编译安装amp并且给php配置xcache机制)
- (四)httpd与php-fpm(rpm)的整合以及php缓存加速模块xcache的安装
- (三)lamp(httpd+php(php为module或是FastCGI)+mysql)centos6(rpm包)
- 基于人工神经网络的五子棋博弈(Details)
- (二)apache之httpd-2.4新特性
- (一)apache(主要是httpd-2.2)的基础配置篇
- TCP零窗口更新与超时重传联合优化的packetdrill确认
- 计算机网络学习笔记
- Android-使用网络获取定位
- 路由表建立的算法
- java网络编程(下)
- 实现基于阿里云负载均衡https证书
- java学习之利用UDP编写网络聊天程序
- Java TCP客户端服务器端交互
- 源码推荐(0724B):网络数据安全--base64 和 MD5 的简单封装,视频播放器封装AVPlayer