套接字的地址格式有很多種,比如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