套接字編程
一、套接字地址結構
大多數套接字函數都需要一個指向套接字地址結構的指針作為參數,每個協議族都定義它自己的套接字地址結構,這些結構的名字均以sockaddr_開頭,並以對應每個協議族的唯一後綴結尾。
1.1 IPv4套接字地址結構
IPv4套接字地址結構通常也稱為“網際套接字地址結構”,它以sockaddr_in命名,定義在<netinet/in.h>頭文件中。以下為POSIX定義:
struct in_addr{ in_addr_t a_addr; //32_bit IPv4 address,network byte ordered };
其中in_addr_t數據類型必須是一個至少32位的無符號整數類型。
struct sockaddr_in{ uint8_t sin_len; //length of structure (16) sa_family_t sin_family; //AF_INET in_port_t sin_port; //16-bit TCP or UDP port number,network byte ordered struct in_addr sin_addr; //32-bit IPv4 address,network byte ordered char sin_zero[8]; //unused };
各結構體成員解析:
1)sin_len:不是所有的廠家都支持這個字段,POSIX規範也不要求這個成員,它是為增加OSI協議的支持而隨4.3BSD-Reno添加的。簡化了長度可變套接字地址結構的處理。除了涉及路由套接字,其他都不需要設置和檢查這個字段。
2)sin_family:指代協議族,socket編程使用AF_INET。數據類型sa_family_t可以是任何無符號整數類型。在支持長度字段的實現中,它通常是一個8位無符號整數,不支持長度字段的實現,則為一個16位的無符號整數。
3)sin_port:端口號,必須是一個至少16位的無符號整數。網絡字節序
4)sin_addr:IP地址,32位無符號整數,網絡字節序。32位IPV4地址存在兩種訪問方法:①serv.sin_addr將按in_addr結構引用其中的32位IPv4地址②serv.sin_addr.s_addr將按in_addr_t引用地址32位IPv4地址。
5)sin_zero:未曾使用,在初始化結構時,我們一般是將整個結構設置為0,而不僅僅是設置sin_zero成員為0。雖然多數結構的使用不要求這一成員為0,但當捆綁一個非通配IPv4地址時,此成員必須為0
註意點:
in_addr結構之前是多種結構的聯合,之後廢除了聯合,所以現在in_addr定義為僅有一個In_addr_t字段的結構。
套接口地址結構僅在給定主機上使用:雖然結構中的某些成員(如IP地址和端口號)用在不同主機間的通信中,但結構本身並不參與通信
1.2 通用套接字地址結構
當作為一個參數傳遞進任何套接字函數時,套接字地址結構總是以引用形式(也就是以指向該結構的指針)來傳遞。但是這樣的話任何套接字函數必須處理來自所支持的任何協議族的套接字地址結構。通用套接字地址結構就是為解決這個問題誕生的。
在<sys/socket.h>頭文件中定義了一個通用的套接字地址結構,如下:
struct sockaddr{ uint8_t sa_len; sa_family_t sa_family; //address family:AF_XXX value char sa_data[14]; //protocol-specific address };
於是,套接字函數被定義為以指向某個通用套接字地址結構的一個指針作為參數之一,如bind函數的ANSI C函數原型:
int bind(int,struct sockaddr *,socklen_t);
也就是說,指向特定協議的套接字地址結構的指針強制轉換成通用套接字地址結構。
struct sockaddr_in serv;
bind(sockfd,(struct sockaddr *)&serv,sizeof(serv));
1.3 IPV6套接字地址結構
IPv6套接字地址結構在<netinet/in.h>頭文件中定義:
struct in6_addr{ uint8_t s6_addr[16]; //128-bit IPv6 address }; #define SIN6_LEN //required for compile-time tests
struct sockaddr_in6{
uint8_t sin6_len; //length of this struct(28) sa_family_t sin6_family; //AF_INET6 in_port_t sin6_port; //transport layer port# network byte ordered uint32_t sin6_flowinfo; //flow information,undefined struct in6_addr sin6_addr; //IPv6 address network byte ordered uint32_t sin6_scope_id; //set of interfaces for a scope };
註意點:
1)如果系統支持套接字地址結構中的長度字段,那麽SIN6_LEN常值必須定義。
2)IPv6的地址族是AF_INET6,而IPv4是AF_INET。
3)結構中字段的先後做過編排,使得如果sockaddr_in6結構本身是64位對齊的,那麽128位的sin6_addr字段也是64位對齊。在一些64位處理機上,如果64位數據存儲在某個64位邊界位置,那麽對它的訪問將得到優化處理。
4)sin6_flowinfo是流標字段,底序20位是流標,高12位保留。
5)對於具備範圍的地址,sin6_scope_id字段標識其範圍。
1.4 新的通用套接字地址結構
作為IPv6套接字API的一部分而定義的新的通用套接字地址結構克服了現有struce sockaddr的一些缺點。其足以容納系統所支持的任何套接字地址結構。sockaddr_storage定義在<netinet/in.h>頭文件中:
struct sockaddr_storage{ uint8_t ss_len; //length of this struct(implementation dependent) sa_family ss_family; //address family:AF_XXX value };
1)如果系統支持的任何套接字地址結構有對齊需要,那麽sockaddr_storage能夠滿足苛刻的對齊要求。
2)sockaddr_storage足夠大,能夠容納系統支持的任何套接字地址結構。
3)除了上面兩個字段(如果有的話),sockaddr_storage結構的其他字段對用戶來說是透明的。
4)sockaddr_storage結構必須類型強制轉換成或復制到適合與ss_family字段所給出地址類型的套接字結構中,才能訪問其他字段。
1.5 套接字地址結構的比較
套接字編程