套接字的地址結構

 

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

發佈了2 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章