IPv4的套接口地址結構爲:編程
struct sockaddr_in { uint8_t sin_len; sa_family_t sin_family; struct in_addr sin_addr; char sin_zero[8]; };
其中最重要的部分當屬sin_addr結構體。這個結構體只有一個元素就是類型爲in_addr_t的32bit的IPv4地址。安全
struct in_addr { in_addr_t s_addr; };
所以假設有一個地址結構addr,要取得地址,addr.in_addr獲得的是一個in_addr類型的結構體;addr.in_addr.s_addr取得的是一in_addr_t 的地址(一般是32位的整數)。數據結構
套接口地址結構在傳遞給套接口函數的時候,老是以指針的方式傳遞。當函數支持不一樣類型協議時,如何聲明函數參數類型使得通用呢?在ANSI C的無類型指針void *出現以前就解決了這個問題。定義了一個標準的通用套接口地址結構:socket
struct sockaddr { uint8_t sin_len; sa_family_t sa_family; char sa_data[14]; };
用戶在使用一些用通用結構類型做爲參數的時候必須進行強制類型轉換(struct sockaddr *),不然編譯器在檢查參數時會給出警告。而內核在處理函數傳入的參數時,經過sockaddr中的sa_family來肯定傳入結構的具體類型。函數
首先要搞清楚爲什麼在socket編程中,結果參數有兩個傳遞方向:從進程到內核和從內核到進程。咱們一般見到的bind,connect,sendto,accept,recvfrom等函數都是系統調用,系統調用時內核提供的函數,也是用戶程序和內核之間的接口。用戶程序在使用系統調用的時候,一般會採用軟中斷的方式陷入到內核中再經過系統調用實現函數的功能。ui
從進程到內核傳遞套接口地址結構的函數有bind,connect和sendto.用戶程序在調用這些函數的時候,將函數的參數傳遞給內核處理,用戶調用這些函數要拷貝多少數據量固然是知道的(換句話說,用戶要求內核拷貝多少數據量確定是知道的),所以函數傳遞的參數是結構的具體大小。如connect所示:spa
struct sockaddr_in serv; connect(sockfd,( struct sockaddr * ) &serv, sizof(serv))
而當函數如accept、recvfrom等在調用時,內核須要向進程返回處理結果,函數調用時傳入的參數是指向結構大小的指針,這個值僅僅是爲了防止內核越界,在執行完成以後,內核將返回儲存的大小,所以在傳入是一個值,函數執行完成以後,將實際的值寫入返回時修改指針指向的大小做爲返回值,這時是結果。指針
本節不止一次提到一個概念:函數不可重入。到底怎樣纔算可重入函數呢?code
可重入,顧名思義就是能夠重複進入。能夠重複進入意味着函數能夠被不一樣的進程調用,而且數據不會出現問題。或者換個說法,可重入的函數能夠在任什麼時候候被中斷去執行另一個任務而不會出現問題。所以在寫可重入函數時,要保證幾點:blog
- 最好不要使用全局變量。若是非要使用,必須用鎖或者信號量對變量進行保護。
- 不使用靜態變量。
- 不調用不可重入函數。
- 保證中斷的安全。
不可重入函數基本有下面幾類:
- 函數體內使用了靜態的數據結構。
- 函數體內使用了全局變量。
- 函數體內調用了malloc()或者free()函數。
- 函數體內調用了標準I/O函數。標準io庫不少實現都以不可重入的方式使用全局數據結構。
- 進行了浮點運算.許多的處理器/編譯器中,浮點通常都是不可重入的。