套接字地址比较

15 篇文章 0 订阅

转自:http://dev.firnow.com/course/6_system/linux/Linuxjs/20100521/203164.html

 

1 struct sockaddr {  

2 unsigned short sa_family;     /* address family, AF_xxx */ 

3 char sa_data[14];                 /* 14 bytes of protocol address */ 

4 };


sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET。
sa_data是14字节协议地址。
此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。 
但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构
sockaddr_in(在netinet/in.h中定义):


显示代码打印01 struct sockaddr_in {  

02 short int sin_family;                      /* Address family */ 

03 unsigned short int sin_port;       /* Port number */ 

04 struct in_addr sin_addr;              /* Internet address */ 

05 unsigned char sin_zero[8];         /* Same size as struct sockaddr */ 

06 };  

07 struct in_addr {  

08 unsigned long s_addr;  

09 };   

10 typedef struct in_addr {  

11 union {  

12             struct{  

13                         unsigned char s_b1,  

14                         s_b2,  

15                         s_b3,  

16                         s_b4;  

17                         } S_un_b;  

18            struct {  

19                         unsigned short s_w1,  

20                         s_w2;  

21                         } S_un_w;  

22             unsigned long S_addr;  

23           } S_un;  

24 } IN_ADDR;

sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序)
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址 
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 
sa_data的含义是由sa_family决定
如果sa_family=AF_INET
则sa_data就是sockaddr_in的sin_addr和sin_port 
换句话说,这时sockaddr可以当作sockaddr_in看


Sockfd是调用socket函数返回的socket描述符,my_addr是个指向包含有本机IP地址及端口号等信息的sockaddr类型的指

针;addrlen常被设置为sizeof(struct sockaddr)。 
  
structsockaddr结构类型是用来保存socket信息的:   

 

显示代码打印1 struct sockaddr {     

2     

3               unsigned short    sa_family; /* 地址族,AF_xxx */  

4   

5               char sa_data[14]; /* 14 字节的协议地址 */  

6                   

7                };

 

            sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;
 
              sa_data则包含该socket的IP地址和端口号。

  
另外更有一种结构类型:   

 

显示代码打印01             struct sockaddr_in {      

02          

03                              short int sin_family; /* 地址族 */ 

04   

05                            unsigned short int sin_port; /* 端口号 */      

06   

07                              struct in_addr sin_addr;/* IP地址 */     

08   

09                              unsigned char sin_zero[8]; /* 填充0 以保持和struct sockaddr同样大小*/     

10   

11                             };  

这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到和struct

sockaddr同样的长度,能用bzero()或memset()函数将其置为零。指向sockaddr_in的指针和指向sockaddr的指针能相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你能在函数调用的时候将一个指向

sockaddr_in的指针转换为指向sockaddr的指针,或相反。

 

以下转自:http://hi.baidu.com/hellosim/blog/item/962c4f27cb73e8b44623e8ee.html

套接字的地址格式有很多种,比如sockaddr、sockaddr_in、sockaddr_ipx、sockaddr_pkt、sockaddr_ll等等,这里就来谈谈他们的区别与联系。

struct sockaddr:

sockaddr是通用的socket地址,定义在include/linux/socket.h“,其具体格式如下:

struct sockaddr {
sa_family_t sa_family;      /* address family, AF_xxx       */
char            sa_data[14];    /* 14 bytes of protocol address */
};

这里的family指的是协议族(或者说协议栈)。主要的协议族有以下:

PF_INET             互联网IPv4
PF_IPX                IPX协议
PF_NETLINK      一个用户空间和内核的接口
PF_PACKET        底层数据包接口

所有这些地址格式都对应着不同的网络协议。这里sockaddr_xxx中的xxx即表明了其所用的网络协议。比如,互联网的socket结构使用struct sockaddr_in,可以与sockaddr进行类型转换。

struct sockaddr_in:

该结构定义在”include/linux/in.h

struct sockaddr_in {
sa_family_t sin_family;     /* Address family               */
__be16 sin_port;       /* Port number                  */
struct in_addr sin_addr;       /* Internet address             */

/* Pad to size of `struct sockaddr’. */
unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};

这里可以看到,之所以可以进行类型转换,是因为在定义sockaddr_in的时候就通过补齐的方法使二者大小一致(并不是所有的sockaddr_xxx都如此)。

/* Internet address. */
struct in_addr {
__be32 s_addr;
};

这个in_addr即是32位的IP地址,在有的版本中也定义为:

struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;
struct { u_short s_w1,s_w2;} S_un_w;
u_long S_addr;
} S_un;
};

利用u_long htonl(u_long hostlong);将主机字节序转换为TCP/IP网络字节序.
利用u_short htons(u_short hostshort);将主机字节序转换为TCP/IP网络字节序.

inet_addr()是将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001)。

以一个典型的互联网套接字程序来说明用法:

int sockfd;
struct sockaddr_in my_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 做一些错误检查! */

my_addr.sin_family = AF_INET; /* 主机字节序 */
my_addr.sin_port = htons(MYPORT); /* short, 网络字节序 */
my_addr.sin_addr.s_addr = inet_addr(“192.168.0.1″);

bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
/* 不要忘了为bind()做错误检查: */
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

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

struct sockaddr_ll

这是一个与设备无关的物理层地址格式,需要使用AF_PACKET协议族,适合用来实现用户态下的网络协议栈。

struct sockaddr_ll
{
unsigned short sll_family;   /* Always AF_PACKET */
unsigned short sll_protocol; /* Physical layer protocol */
int            sll_ifindex; /* Interface number */
unsigned short sll_hatype;   /* Header type */
unsigned char sll_pkttype; /* Packet type */
unsigned char sll_halen;    /* Length of address */
unsigned char sll_addr[8]; /* Physical layer address */

};

----------------------

References:

Linux Kernel Version 2.6.22

http://blog.csdn.net/zysee/archive/2007/01/16/1484235.aspx

===============补充=================

以太网头部结构,一共14个字节:

104 struct ethhdr {
105 unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
106 unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
107 __be16 h_proto;                /* packet type ID field */
108 } __attribute__((packed));

ETH_ALEN被定义为6,即以太网MAC地址的长度。h_proto在I386和arm上都是unsigned long类型,它用来保存type的值。type是接口的硬件类型,以太网设备的初始化函数中将其赋值为ARPHRD_ETHER,即10Mb以太网。具体的类型定义在/usr/include/linux/if_arp.h中。如有需要,可以考虑定义自己的网络类型(比如ARPHDR_AQUANET之类的)。

(Kernel Version 2.6.18)

===============补充2=================

UNIX套接字 sockaddr_un

这是和AF_LOCAL搭配使用创建本地套接字的,是一种进行本地进程间IPC的方法。

  
  
/* Structure describing the address of an AF_LOCAL (aka AF_UNIX) socket. */ struct sockaddr_un { __SOCKADDR_COMMON (sun_); char sun_path[108]; /* Path name. */ };

注意,在调用connect/bind/accept时,要强制类型转换为(struct sockadd *)格式,否则编译时会报告指针类型错误,比如:

  
  
warning: passing argument 2 of connect from incompatible pointer type warning: passing argument 2 of bind from incompatible pointer type warning: passing argument 2 of accept from incompatible pointer type

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值