注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

长风明志的博客

不要也不能做下一个谁,应该且可以做第一个自己

 
 
 

日志

 
 

Linux网络编程sockaddr和sockaddr_in 解析及IP地址处理  

2011-05-15 10:12:50|  分类: Unix/Linux |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Linux网络数据结构
在网络实际传送的数据中,有两种字节排列顺序:重要的字节在前面,或者不重要的
字节在前面。 前一种叫网络字节顺序(Network Byte Order,NBO),有些机器在内部
是按照这个顺序储存数据的。当某数据必须按照NBO顺 序时,那么要调用函数(例如htons
())将它从本机字节顺序(Host Byte Order,HBO)转换过来,否则传送过去的数据将
使 对方机器不可读。这点对于网络数据传送来说是非常关键的。
在网络中第一个被创造的结构类型是sockaddr。这个数据结构是为许多类 型的套接口
储存地址信息。它的定义如下:
struct sockaddr{
  unsigned short  sa_family; /*这个是地址族,通常是AF-xxxx的形式*/
  char  sa_data[14];     /*14字节的地址信息*/
  };
sa_family是地址家族,是“AF_xxx”的形式。常设为“AF_INET”,代表Internet(TCP/IP)地址族。
   sa_data是协议地址,由sa_family决定。如果sa_family=AF_INET,则sa_data就是sockaddr_in的 sin_addr和sin_port,用于为套接口储存目标地址和端口信息。为了解决struct sockaddr,创造了一个并列的结构struct sockadd_in(“in”代表
“Internet”),换句话说,这时sockaddr可以当作sockaddr_in看。
如下所示:

struct sockaddr_in{
short int   sin_family;  /*地址族信息,通常是AF-xxxx的形式*/
unsigned short    int sin_port; /*端口信息*/
struct in_addr    sin_addr;     /*网络地址*/
unsigned char     sin_zero[8];  /*补位用的0,to make same size as struct sockaddr*/
}
struct in_addr {
unsigned long s_addr;
};

typedef struct in_addr {
union {
   struct{
      unsigned char s_b1,
     s_b2,
     s_b3,
     s_b4;
   } S_un_b;
struct {
    unsigned short s_w1,
    s_w2;
   } S_un_w;
unsigned long S_addr;
 } S_un;
} IN_ADDR;

      sin_family意义与sa_family同。
  sin_port存储端口号(使用网络字节顺序)
  sin_addr存储IP地 址,使用in_addr这个数据结构
  sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空 字节。
  在 in_addr结构体中,s_addr按照网络字节顺序存储IP地址。考试大-全国最大 教育类网站(www.Examda。com)
  sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。指向sockaddr_in的指针和指向sockaddr的指针可 以相互转换,这意味着如果一个函数所需参数类型是sockaddr类型时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向 sockaddr的指针;或者相反。总之,sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体 的指针也可以指向sockadd的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,在最后用进行类型转换就可以了。

bzero((char*)&mysock,sizeof(mysock));//初始化
mysock结构体名
mysock.sa_family=AF_INET;
mysock.sin_addr.s_addr=inet_addr("192.168.0.1");
……
等到要做转换的时候用:
(struct sockaddr*)mysock

进行网络编程,使用socket, listen, bind等函数。
你只要记住,填值的时候使用sockaddr_in结构,而作为函数的参数传入的时候转换成sockaddr结构就行了,毕竟都是16个字符长。



上 面这个数据结构可以轻松处理套接口地址的基本元素。需要解释的是,sin_zero被
加入到这个结构中主要是为了保证struct sockaddr的数据长度和struct sockaddr_in
的一样,这样在使用标准函数时,就可以使用统一的数据接口。需要注意的是, 应该
使用函数bzero()将sin_zero全部置零。最后,sin_port和sin_addb必须是网络字节
顺序 (Network Byte Order)。如果声明“inadd”是数据结构stmct sockaddr_in的实
例,那么 inadd.sinadd.s_addr就储存了4个字节的IP地址(网络字节顺序)。

另一个常用到的是unsigned类型。它比上 面介绍的struct sockaddr_in或struct sockaddr
用得更普遍。对于变量类型unsigned,可以使用的两种类 型是short(两个字节)和long
(四个字节)。假设想将short从本机字节顺序转换为网络字节顺序,需用“h”表示本
机 (host),用“to”表示进行转换,然后用“n”表示网络,用“s”表示short,那
么就是h-to-n-s或者htons() (“Host to Network Short”)。

考虑到对不同机器的可移值性,这样的转换是必需的。我们对“n”、“h”、 “s”
和“l”这几个字母进行组合,就可以得到Linux下的全部转换函数。
IP地址在Linux网络中的处理方法:
假设使用struct sockaddr_in ina,想将IP地址“164.112.175.124”储存到其中
, 那么所要做的是调用函数inet_addr(),转换上面“数字 + 句点”格式的IP地址到
unsigned long中
。这个工作可以这样来做:

ina.sin_addr.s_addr=inet_addr(”164.112.175.124”);
inet_addr()返回的地址已经是按照网络字节顺序的,不用调用htonl()。在发生错误
的时 候inet_addr()返回-1。调用后,需使用正确的错误检查,比如说当IP地址为255
.255.255.255的时候,返回的就是 (unsigned)-1。因为这是个广播地址,你的程
序必需能够将这类错误捕获出来。

你现在就可以转换字符串形式的IP地 址为1ong了。若有一个数据结构struct in_addr
,按照“数字+句点”格式打印时
,你要用函数inet_ntoa()(ntoa 意思是network to
 ascⅡ),如下所示:

printf(“%s”,inet_ntoa(ina.sin_addr));
这样就可以打印IP地址。注意:函数inet_ntoa()的参数是struct in_addr,而不是
long, 它返回的是一个指向字符的指针。

在inet_ntoa内储存了字符数组,因此它每次调用inet_ntoa()的时候将覆盖以前的内
容。

例如:

Char a1,  *a2;
......
a1=inet_ntoa(ina1.sin_addr); /*假设地址是;164.112.175.124*/
a2=inet_ntoa(ina2.sin_addr);/*假设地址 是:202.112.58.200*/
printf(“address 1:%s\n”,a1);
printf(“address 2:%s\n”,a2);
 
上面运行结果是:

address l:202.112.58.200
address 2:202.112.58.200
 


如果想保存地址,那么可用strcpy()保存到自 己的字符数组中。
  评论这张
 
阅读(417)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017