2024年2月20日发(作者:)
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结构体名
_family=AF_INET;
_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的实
例,那么 .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中。这个工作可以这样来做:
_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(_addr));
这样就可以打印IP地址。注意:函数inet_ntoa()的参数是struct in_addr,而不是
long, 它返回的是一个指向字符的指针。
在inet_ntoa内储存了字符数组,因此它每次调用inet_ntoa()的时候将覆盖以前的内
容。
例如:
Char a1, *a2;
......
a1=inet_ntoa(_addr); /*假设地址是;164.112.175.124*/
a2=inet_ntoa(_addr);/*假设地址 是:202.112.58.200*/
printf(“address 1:%sn”,a1);
printf(“address 2:%sn”,a2);
上面运行结果是:
address l:202.112.58.200
address 2:202.112.58.200
发布评论