socket能夠當作是用戶進程與內核網絡協議棧的編程接口。TCP/IP協議的底層部分已經被內核實現了,而應用層是用戶須要實現的,這部分程序工做在用戶空間。用戶空間的程序須要經過套接字來訪問內核網絡協議棧。html
套接口是全雙工的通訊,它不只能夠用於本機的進程間通訊,還能夠用於網絡上不一樣主機的進程間通訊。編程
套接字還能夠異構系統間進行通訊,異構系統指的是在硬件或軟件上有所差異的系統,例如安卓系統的手機與windows系統的PC機上均可以實現QQ通訊,套接字能夠實如今這兩個設備上的通訊。windows
套接口既然可以鏈接兩個端系統,那它就須要一個地址來標記該端系統,例如兩個電話須要電話號碼來標記才能夠進行撥號。這抽象成套接口的地址結構。IPV4套接口地址結構一般也稱爲「網際套接字地址結構」,它以sockaddr_in命名,定義在頭文件< netinet/in/h >中。網絡
struct sockaddr_in{ uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8]; };
說明:socket
其中,struct in_addr僅僅是一個32位的無符號整數,能夠在終端下輸入man 7 ip進行查看:函數
接下來看一下通用的地址結構。上面說過,socket能夠用於不一樣的協議上,通用的地址結構能夠用於任何協議的socket編程。測試
struct sockaddr{ uint8_t sin_len; sa_family sin_family; char sa_data[14]; };
說明:ui
能夠看到,在通用地址結構中sa_data是14個字節,而在IPV4的地址結構中,sin_port、sin_addr、sin_zero三個變量加起來也等於14個字節。也便是說,這兩種結構是兼容的。設計
字節序能夠分爲大端字節序與小端字節序:unix
這樣提及來挺抽象,經過一幅圖來講明:
上面說過,socket能夠用於異構系統之間的通訊。而不一樣的系統採用的字節序多是不一樣的,有的系統採用大端字節序,例如Motorola 6800;有的採用小端字節序,如X86。所以,在進行字節傳輸時,應該同一一個字節序,稱爲網絡字節序。網絡字節序採用大端字節序。若是主機A爲小端字節序的系統,那麼在傳輸時須要先將小端字節序轉換成網絡字節序。這須要一些字節序的轉換函數。
咱們能夠編寫程序來測試本身的主機是什麼字節序:
#include<stdio.h> int main(void) { unsigned int x = 0x12345678; unsigned char *p = (unsigned char*)&x; printf("%0x,%0x,%0x,%0x\n",p[0],p[1],p[2],p[3]); return 0; }
在個人電腦上輸出結果爲:78,56,34,12. 所以個人主機爲小端字節序。
若是主機的字節序與網絡字節序不一樣,那麼須要進行字節序的轉換。下面是一些字節序轉換函數:
# include < arpa/inet.h > uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
說明:h表明host;n表明network;s表明short;l表明long
描述:
咱們能夠進行驗證,剛纔已經經過程序測試出個人主機是小端字節序,接下來使用函數 htonl()將整數0x12345678轉換成網絡字節序。
#include<stdio.h> #include <arpa/inet.h> int main(void) { unsigned int x = 0x12345678; unsigned char *p = (unsigned char*)&x; printf("轉換前:%0x,%0x,%0x,%0x\n",p[0],p[1],p[2],p[3]); unsigned int y = htonl(x); p = (unsigned char *) &y; printf("轉換後:%0x,%0x,%0x,%0x\n",p[0],p[1],p[2],p[3]); return 0; }
結果輸出:
轉換前:78,56,34,12
轉換後:12,34,56,78
對於IP地址,咱們一般採用點分十進制的形式進行直觀的認識,而程序更多的時候是處理32位的地址,所以須要有函數在點分十進制與32位地址這兩種形式間進行轉換。
# include < sys/socket.h> # include < netinet/in.h> # include < arpa/inet.h> int inet_aton(const char *cp, struct in_addr *inp); in_addr_t inet_addr(const char *cp); char *inet_ntoa(struct in_addr in);
描述:
例程:
#include<stdio.h> #include<arpa/inet.h> int main() { unsigned long addr = inet_addr("192.168.0.100");//將點分十進制轉換爲32bit地址 printf("addr = %u\n",htonl(addr)); struct in_addr ipaddr; ipaddr.s_addr = addr; printf("ipaddr = %s\n",inet_ntoa(ipaddr)); //網絡字節序地址轉換爲點分十>進制 return 0; }
輸出:
addr = 3232235620
ipaddr = 192.168.0.100
套接字類型主要有三種: