C函數篇(setsockopt函數②)

套接口選項  

在前面的幾章中,咱們討論了使用套接口的基礎內容。如今咱們要來探討一些可用的其餘的特徵。在咱們掌握了這一章的概念以後,咱們就爲後面的套接口的高級主題作好了準備。在這一章,咱們將會專一於下列主題:
如何使用getsockopt(2)函數得到套接口選項值
如何使用setsockopt(2)函數設置套接口選項值
如何使用這些經常使用的套接口選項

獲得套接口選項

有時,一個程序須要肯定爲當前爲一個套接口進行哪些選項設置。這對於一個子程序庫函數尤爲如此,由於這個庫函數並不知道爲這個套接口進行哪些設置,而這個套接口須要做爲一個參數進行傳遞。程序也許須要知道相似於流默認使用的緩衝區的大小。

容許咱們獲得套接口選項值的爲getsockopt函數。這個函數的概要以下:
程序員

1 #include <sys/types.h>
2 #include <sys/socket.h>
3 int getsockopt(int s,
4     int level,
5     int optname,
6     void *optval,
7     socklen_t *optlen);

 

函數參數描述以下:
1 要進行選項檢驗的套接口s
2 選項檢驗所在的協議層level
3 要檢驗的選項optname
4 指向接收選項值的緩衝區的指針optval
5 指針optlen同時指向輸入緩衝區的長度和返回的選項長度值

當函數成功時返回0。當發生錯誤時會返回-1,而錯誤緣由會存放在外部變量errno中。

協議層參數指明瞭咱們但願訪問一個選項所在的協議棧。一般咱們須要使用下面中的一個:
SOL_SOCKET來訪問套接口層選項
SOL_TCP來訪問TCP層選項

咱們在這一章的討論將會專一於SOL_SOCKET層選項的使用。

參數optname爲一個整數值。在這裏所使用的值首先是由所選用的level參數來肯定的。在一個指定的協議層,optname參數將會肯定咱們但願訪問哪個選項。下表列出了一些層與選項的組合值:

協議層        選項名字
SOL_SOCKET    SO_REUSEADDR
SOL_SOCKET    SO_KKEPALIVE
SOL_SOCKET    SO_LINGER
SOL_SOCKET    SO_BROADCAST
SOL_SOCKET    SO_OOBINLINE
SOL_SOCKET    SO_SNDBUF
SOL_SOCKET    SO_RCVBUF
SOL_SOCKET    SO_TYPE
SOL_SOCKET    SO_ERROR
SOL_TCP        SO_NODELAY

上表所列的大多數選項爲套接口選項,其中的層是由SOL_SOCKET指定的。爲了比較的目的包含了一個TCP層套接口選項,其中的層是由SOL_TCP指定的。

大多數套接口選項得到後存放在int數據類型中。當查看手冊頁時,數據類型int一般會有一些假設,除非代表了其餘東西。當使用一個布爾值時,當值爲非零時,int表示TRUE,而若是爲零,則表示FALSE。

應用getsockopt(2)

在這一部分,咱們將會編譯並運行一個getsndrcv.c的程序,這個程序會得到並報告一個套接口的發送以及接收緩衝區的大小尺寸。
服務器

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <errno.h>
 6 #include <sys/types.h>
 7 #include <sys/socket.h>
 8 #include <assert.h>
 9 
10 
11 static void bail(const char *on_what)
12 {
13     if(errno != 0)
14     {
15     fputs(strerror(errno),stderr);
16     fputs(": ",stderr);
17     }
18     fputs(on_what,stderr);
19     fputc('/n',stderr);
20     exit(1);
21 }
22 
23 int main(int argc,char **argv)
24 {
25     int z;
26     int s=-1;            
27     int sndbuf=0;        
28     int rcvbuf=0;        
29     socklen_t optlen;        
30 
31    
32     s = socket(PF_INET,SOCK_STREAM,0);
33     if(s==-1)
34     bail("socket(2)");
35 
36    
37     optlen = sizeof sndbuf;
38     z = getsockopt(s,SOL_SOCKET,SO_SNDBUF,&sndbuf,&optlen);
39 
40     if(z)
41     bail("getsockopt(s,SOL_SOCKET,"
42         "SO_SNDBUF)");
43 
44     assert(optlen == sizeof sndbuf);
45 
46    
47 
48     optlen = sizeof rcvbuf;
49     z = getsockopt(s,SOL_SOCKET,SO_RCVBUF,&rcvbuf,&optlen);
50     if(z)
51     bail("getsockopt(s,SOL_SOCKET,"
52         "SO_RCVBUF)");
53 
54     assert(optlen == sizeof rcvbuf);
55 
56    
57     printf("Socket s: %d/n",s);
58     printf("Send buf: %d bytes/n",sndbuf);
59     printf("Recv buf: %d bytes/n",rcvbuf);
60 
61     close(s);
62     return 0;
63 }

 

程序的運行結果以下:
$ ./getsndrcv
socket s : 3
  Send buf: 65535 bytes
  Recv buf: 65535 bytes

設置套接口選項

若是認爲套接口的默認發送以及接收緩衝區的尺寸太大時,做爲程序設計者的咱們能夠將其設計爲一個小的緩衝區。當咱們程序一個程序的幾個實例同時運行在咱們的系統上時,這顯得尤爲重要。

能夠經過setsockopt(2)函數來設計套接口選項。這個函數的概要以下:
網絡

1 #include <sys/types.h>
2 #include <sys/socket.h>
3 int setsockopt(int s,
4     int level,
5     int optname,
6     const void *optval,
7     socklen_t optlen);

 


這個函數與咱們在上面所討論的getsockopt函數相似,setsockopt函數的參數描述以下:
1 選項改變所要影響的套接口s
2 選項的套接口層次level
3 要設計的選項名optname
4 指向要爲新選項所設置的值的指針optval
5 選項值長度optlen

這個函數參數與上面的getsockopt函數的參數的區別就在於最後一個參數僅是傳遞參數值。在這種狀況下只是一個輸入值。

應用setsockopt函數

下面的例子代碼爲一個套接口改變了發送以及接收緩衝區的尺寸。在設置完這些選項之後,程序會獲得並報告實際的緩衝區尺寸。
併發

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <string.h>
 5 #include <errno.h>
 6 #include <sys/types.h>
 7 #include <sys/socket.h>
 8 #include <assert.h>
 9 
10 
11 static void bail(const char *on_what)
12 {
13     if(errno!=0)
14     {
15     fputs(strerror(errno),stderr);
16     fputs(": ",stderr);
17     }
18     fputs(on_what,stderr);
19     fputc('/n',stderr);
20     exit(1);
21 }
22 
23 int main(int argc,char **argv)
24 {
25     int z;
26     int s=-1;            
27     int sndbuf=0;        
28     int rcvbuf=0;        
29     socklen_t optlen;        
30 
31    
32     s = socket(PF_INET,SOCK_STREAM,0);
33     if(s==-1)
34     bail("socket(2)");
35 
36    
37     sndbuf = 5000;    
38     z = setsockopt(s,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof sndbuf);
39     if(z)
40     bail("setsockopt(s,SOL_SOCKET,"
41         "SO_SNDBUF)");
42 
43    
44     rcvbuf = 8192;    
45     z = setsockopt(s,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof rcvbuf);
46     if(z)
47     bail("setsockopt(s,SOL_SOCKET,"
48         "SO_RCVBUF)");
49 
50    
51     optlen = sizeof sndbuf;
52     z = getsockopt(s,SOL_SOCKET,SO_SNDBUF,&sndbuf,&optlen);
53     if(z)
54     bail("getsockopt(s,SOL_SOCKET,"
55         "SO_SNDBUF)");
56 
57     assert(optlen == sizeof sndbuf);
58 
59    
60     optlen = sizeof rcvbuf;
61     z = getsockopt(s,SOL_SOCKET,SO_RCVBUF,&rcvbuf,&optlen);
62     if(z)
63     bail("getsockopt(s,SOL_SOCKET"
64         "SO_RCVBUF)");
65     assert(optlen == sizeof rcvbuf);
66 
67    
68     printf("Socket s: %d/n",s);
69     printf(" Send buf: %d bytes/n",sndbuf);
70     printf(" Recv buf: %d bytes/n",rcvbuf);
71 
72     close(s);
73     return 0;
74 }

 

程序的運行結果以下:
$ ./setsndrcv
Socket s : 3
  Send buf: 10000 bytes
  Recv buf: 16384 bytes
$

在 這裏咱們要注意程序所報告的結果。他們看上去彷佛是所指定的原始尺寸的兩倍。這個緣由能夠由Linux內核源碼模塊net/core/sock.c中查 到。咱們能夠查看一下SO_SNDBUF以及SO_RCVBUF的case語句。下面一段是由內核模塊sock.c中摘錄的一段處理SO_SNDBUF的 代碼:
框架

398        case SO_SNDBUF:
399                        
403                            
404                         if (val > sysctl_wmem_max)
405                                 val = sysctl_wmem_max;
406 set_sndbuf:
407                         sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
408                         if ((val * 2) < SOCK_MIN_SNDBUF)
409                                 sk->sk_sndbuf = SOCK_MIN_SNDBUF;
410                         else
411                                 sk->sk_sndbuf = val * 2;
412
413                        
417                         sk->sk_write_space(sk);
418                         break;

 


由這段代碼咱們能夠看到實際發生在SO_SNDBUF上的事情:
1 檢測SO_SNDBUF選項值來肯定他是否超過了緩衝區的最大值
2 若是步驟1中的SO_SNDBUF選項值沒有超過最大值,那麼就使用這個最大值,而不會向調用者返回錯誤代碼
3 若是SO_SNDBUF選項值的2倍小於套接口SO_SNDBUF的最小值,那麼實際的SO_SNDBUF則會設置爲SO_SNDBUF的最小值,不然則會SO_SNDBUF選項值則會設置爲SO_SNDBUF選項值的2倍

從這裏咱們能夠看出SO_SNDBUF的選項值只是所用的一個提示值。內核會最終肯定爲SO_SNDBUF所用的最佳值。

查看更多的內核源碼,咱們能夠看到相似的狀況也適用於SO_RCVBUF選項。以下面的一段摘錄的代碼:
socket

427                 case SO_RCVBUF:
428                        
432                           
433                         if (val > sysctl_rmem_max)
434                                 val = sysctl_rmem_max;
435 set_rcvbuf:
436                         sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
437                        
452                         if ((val * 2) < SOCK_MIN_RCVBUF)
453                                 sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
454                         else
455                                 sk->sk_rcvbuf = val * 2;
456                         break;

 


取得套接口類型

實際上咱們只能夠獲得一些套接口選項。SO_TYPE就是其中的一例。這個選項會容許傳遞套接口的一個子函數來肯定正在處理的是哪種套接口類型。

以下面是一段獲得套接口s類型的示例代碼:
函數

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <string.h>
 5 #include <errno.h>
 6 #include <sys/types.h>
 7 #include <sys/socket.h>
 8 #include <assert.h>
 9 
10 
11 static void bail(const char *on_what)
12 {
13     if(errno!=0)
14     {
15     fputs(strerror(errno),stderr);
16     fputs(": ",stderr);
17     }
18     fputs(on_what,stderr);
19     fputc('/n',stderr);
20     exit(1);
21 }
22 
23 int main(int argc,char **argv)
24 {
25     int z;
26     int s = -1;            
27     int so_type = -1;        
28     socklen_t optlen;        
29 
30    
31     s = socket(PF_INET,SOCK_STREAM,0);
32     if(s==-1)
33     bail("socket(2)");
34 
35    
36     optlen = sizeof so_type;
37     z = getsockopt(s,SOL_SOCKET,SO_TYPE,&so_type,&optlen);
38     if(z)
39     bail("getsockopt(s,SOL_SOCKET,"
40         "SO_TYPE)");
41     assert(optlen == sizeof so_type);
42 
43    
44     printf("Socket s: %d/n",s);
45     printf(" SO_TYPE : %d/n",so_type);
46     printf(" SO_STREAM = %d/n",SOCK_STREAM);
47 
48     close(s);
49     return 0;
50 }

 

程序的運行結果以下:
$./gettype
Socket s: 3
 SO_TYPE : 1
 SO_STREAM = 1

設置SO_REUSEADDR選項

在第11章,"併發客戶端服務器"的第一部分中,提供並測試了一個使用fork系統調用設計的服務器。圖12.1顯示了在一個telnet命令與服務器創建鏈接以後的三個步驟。
這些步驟以下:
1 啓動服務器進程(PID 926)。他監聽客戶端鏈接。
2 啓動客戶端進程(telnet命令),而且鏈接到服務器進程(PID 926)。
3 經過fork調用建立服務器子進程,這會保留的原始的父進程(PID 926)而且建立一個新的子進程(PID 927)。
4 鏈接的客戶端套接口由服務器父進程(PID 926)關閉,僅在子進程(PID 927)中保持鏈接的客戶端套接口處理打開狀態。
5 telnet命令與服務器子進程(PID 927)隨意交互,而獨立於父進程(PID 926)。

在步驟5,有兩個套接口活動:
服務器(PID 926)監聽192.168.0.1:9099
客戶端由套接口192.168.0.1:9099進行服務(PID 927),他鏈接到客戶端地址192.168.0.2:1035

客戶端由進程ID 927進行服務。這意味着咱們能夠殺掉進程ID 926,而客戶端仍能夠繼續被服務。然而,卻不會有新的鏈接鏈接到服務器,由於並無服務器監聽新的鏈接(監聽服務器PID 926已被殺死)

現 在若是咱們重啓服務器來監聽新的鏈接,就會出現問題。當新的服務器進程試着綁定IP地址192.168.0.1:9099時,bind函數就會返回 EADDRINUSE的錯誤代碼。這個錯誤代碼代表IP已經在9099端口上使用。這是由於進程PID 927仍然在忙於服務一個客戶端。地址192.168.0.1:9099仍爲這個進程所使用。

這個問題的解決辦法就是殺掉進程927,這個關閉套接口而且釋放IP地址和端口。然而,若是正在被服務的客戶是咱們所在公司的CEO,這樣的作法彷佛不是一個選擇。同時,其餘的部門也會抱怨咱們爲何要從新啓動服務器。

這個問題的一個好的解決辦法就是使用SO_REUSEADDR套接口選項。全部的服務器都應使用這個選項,除非有一個更好的理由不使用。爲了有效的使用這個選項,咱們應在監聽鏈接的服務器中執行下面的操做:
1 使用一般的socket函數建立一個監聽套接口
2 調用setsockopt函數設置SO_REUSEADDR爲TRUE
3 調用bind函數

套接口如今被標記爲可重用。若是監聽服務器進程由於任何緣由終止,咱們能夠從新啓動這個服務器。當一個客戶正爲另外一個服務器進程使用同一個IP和端口號進行服務時尤爲如此。

爲了有效的使用SO_REUSEADDR選項,須要考慮下面的狀況:
在監聽模式下並無一樣的IP地址和端口號的其餘套接口
全部的同一個IP地址和端口號的套接口必須將SO_REUSEADDR選項設置爲TRUE

這就意味着一個指定的IP地址和端口號對上只能夠用一個監聽器。若是這樣的套接口已經存在,那麼設置這樣的選項將不會達到咱們的目的。

只有全部存在的同一個地址和端口號的套接口有這個選項設置,將SO_REUSEADDR設置爲TRUE纔會有效。若是存在的套接口沒有這個選項設置,那麼bind函數就會繼續而且會返回一個錯誤號。

下面的代碼顯示如何將這個選項設置爲TRUE:
測試

1 #define TRUE 1
2 #define FALSE 0
3 int z;     
4 int s;   
5 int so_reuseaddr = TRUE;
6 z = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,
7     &so_reuseaddr,
8     sizeof so_reuseaddr);

 


若是須要SO_REUSEADDR選項能夠由getsockopt函數進行查詢。

設置SO_LINGER選項

另外一個經常使用的選項就是SO_LINGER選項。與SO_REUSEADDR選項所不一樣的是這個選項所用的數據類型並非一個簡單的int類型。

SO_LINGER選項的目的是控制當調用close函數時套接口如何關閉。這個選項只適用於面向鏈接的協議,例如TCP。

內核的默認行爲是容許close函數當即返回給調用者。若是可能任何未發送的TCP/IP數據將會進行傳送,可是並不會保證這樣作。由於close函數會當即向調用者返回控制權,程序並無辦法知道最後一位的數據是否進行了發送。

SO_LINGER選項能夠做用在套接口上,來使得程序阻塞close函數調用,直到全部最後的數據傳送到遠程端。並且,這會保證兩端的調用知道套接口正常關閉。若是失敗,指定的選項超時,而且向調用程序返回一個錯誤。

經過使用不一樣的SO_LINGER選項值,能夠應用一個最後場景。若是調用程序但願當即停止通訊,能夠在linger結構中設置合適的值。而後,一個到close的調用會初始化一個通訊停止鏈接,而丟棄全部未發送的數據,並當即關閉套接口。

SO_LINGER的這種操做模式是由linger結構來控制的:
struct linger {
    int    l_onoff;
    int    l_linger;
};
成員l_onoff爲一個布爾值,非零值表示TRUE,而零則表示FALSE。這個選項的三個值描述以下:

1 設置l_onoff爲FALSE使得成員l_linger被忽略,而使用默認的close行爲。也就是說,close調用會當即返回給調用者,若是可能將會傳輸任何未發送的數據。
2 設置l_onoff爲TRUE將會使得成員l_linger的值變得重要。當l_linger非零時,這表明應用在close函數調用上的以秒計的超時時 限。若是超時發生以前,有未發送的數據而且成功關閉,函數將會成功返回。不然,將會返回錯誤,而將變量errno的值設置爲EWOULDBLOCK。
3 將l_onoff設置爲TRUE而l_linger設置爲零時使得鏈接停止,在調用close時任何示發送的數據都會丟棄。

我 們也許但願獲得一些建議,在咱們的程序中使用SO_LINGER選項,而且提供一個合理的超時時限。而後,能夠檢測由close函數的返回值來肯定鏈接是 否成功關閉。若是返回了一個錯誤,這就告知咱們的程序也許遠程程序並不能接收咱們發送的所有數據。相對的,他也許僅意味着鏈接關閉時發生的問題。

然 而,咱們必須保持清醒,這樣的方法在一些服務器設計中會產生新的問題。當在close函數調用上將SO_LINGER選項配置爲超時(linger),當 咱們的服務器在close函數調用中執行超時時會阻止其餘的客戶端進行服務。若是咱們正在一個進程中服務多個客戶端進程時就會存在這個問題。使用默認的行 爲也許更爲合適,由於這容許close函數當即返回。而任何未發送的數據也會爲內核繼續發送。

最後,若是程序或是服務器知道鏈接應什麼時候停止時可使用停止行爲。這也許適用於當服務器認爲沒有訪問權限的用戶正試着進行訪問的狀況。這種狀況下的客戶並不會獲得特別的關注。

下面的代碼是一個使用SO_LINGER選項的例子,使用30秒的超時時限:
spa

 1 #define TRUE     1
 2 #define FALSE    0
 3 int z; int s;      
 4 struct linger so_linger;
 5 ...
 6 so_linger.l_onoff = TRUE;
 7 so_linger.l_linger = 30;
 8 z = setsockopt(s,
 9     SOL_SOCKET,
10     SO_LINGER,
11     &so_linger,
12     sizeof so_linger);
13 if ( z )
14    perror("setsockopt(2)");

 


下面的例子顯示瞭如何設置SO_LINGER的值來停止套接口s上的當前鏈接:
設計

 1 #define TRUE     1
 2 #define FALSE    0
 3 int z;
 4 int s;      
 5 struct linger so_linger;
 6 ...
 7 so_linger.l_onoff = TRUE;
 8 so_linger.l_linger = 0;
 9 z = setsockopt(s,
10     SOL_SOCKET,
11     SO_LINGER,
12     &so_linger,
13     sizeof so_linger);
14 if ( z )
15     perror("setsockopt(2)");
16     close(s);

 


在上面的這個例子中,當調用close函數時,套接口s會當即停止。停止的語義是經過將超時值設置爲0來實現的。

設置SO_KKEPALIVE選項

當使用鏈接時,有時他們會空閒至關長的時間。例如,創建一個telnet會話經過訪問股票交易服務。他也許會執行一些初始的查詢,而後離開鏈接而保持服務打開,由於他但願回來查詢更多的內容。然而,同時鏈接處理空閒狀態,也許一次就是一個小時。

任 何一個服務器認爲他有一個鏈接的客戶時會爲其分配相應的資源。若是服務器是一個派生類型(fork),那麼整個Linux進程及其相應的內存都分配給這個 客戶。若是事情順利,這個場景並不會產生任何問題。然而當出現網絡崩潰時,困難出現了,咱們全部的578個客戶都會從咱們的股票交易服務中失去鏈接。

在網絡服務恢復後,578個客戶會試着鏈接到咱們的服務器,重建鏈接。這對於咱們來講是一個真實的問題,由於咱們的服務器在以前並無意識到他失去了空閒客戶--SO_KKEPALIVE來解決這個問題。

下面的例子顯示瞭如何在套接口s上使用SO_KKEPALIVE選項,從而一個斷開的空閒鏈接能夠被檢測到:

 1 #define TRUE    1
 2 #define FALSE   0
 3 int z; int s;
 4 int so_keepalive;
 5 ...
 6 so_keepalive = TRUE;
 7 z = setsockopt(s,
 8     SOL_SOCKET,
 9     SO_KEEPALIVE,
10     &so_keepalive,
11     sizeof so_keepalive);
12 if ( z )
13     perror("setsockopt(2)");

 

在上面的例子中設置了SO_KEEPALIVE選項,這樣當套接口鏈接空閒至關長的時間時,一個探測信息(probe message)就會發送到遠程端。這一般是在兩個小時的無活動後完成的。對於一個保持活動的探測信息會有三個可能的反應。他們分別是:
1 端會合適的返回代表一切正常。並無向程序返回任何指示信息,由於這是程序假定的開始。
2 端響應代表他對鏈接一無所知。這代表端自上次通訊之後與主機進行從新鏈接。這樣當下次套接口操做時會向程序返回ECONNRESET錯誤代碼。
3 端沒有響應。在這種狀況下,內核也許作了幾回嘗試進行鏈接。若是沒有響應請求,TCP一般會在大約11分鐘內放棄。當這種狀況發生時,在下次套接口操做時會返回ETIMEOUT錯誤。其餘的錯誤,例如EHOSTUNREACH會在網絡再也不能到達主機時返回。

SO_KEEPALIVE 所調用的時間框架會限制他一般的用處。探測信息也只在大約兩個小時的無活動後纔會發送。而後,當沒有響應時,在鏈接返回錯誤時還須要另外的11分鐘。不管 怎樣,這個選項確實容許探測空閒的無鏈接套接口,而後由服務器進行關閉。相應的,支持長空閒鏈接的服務器應容許這個特徵。

設置SO_BROADCAST選項

咱們如今尚未討論到使用UDP進行廣播的主題。然而,咱們很容易意識到廣播功能的誤用以及所形成的網絡災難。爲了不在沒有計劃廣播時進行廣播,套接口禁用了廣播功能。若是確實須要廣播,那麼C程序員要爲套接口的這個功能處理相應的麻煩。

SO_BROADCAST是一個布爾標誌選項,由int數據類型進行設置。下面的例子顯示瞭如何設置SO_BROADCAST選項:

 1 #define TRUE    1
 2 #define FALSE   0
 3 int z;
 4 int s;    
 5 int so_broadcast;
 6 ...
 7 so_broadcast = TRUE;
 8 z = setsockopt(s,
 9     SOL_SOCKET,
10     SO_BROADCAST,
11     &so_broadcast,
12     sizeof so_broadcast);
13 if ( z )
14     perror("setsockopt(2)");

 

若是要setsockopt函數返回零,套接口s已經容許進行廣播。然而在這裏要注意的是所選用的套接口類型必須具備廣播功能,例如UDP套接口。

設置SO_OOBINLINE選項

在一些狀況下,已發送的數據也許會超過所限制的數據量。一般,這些越界的數據是用不一樣於一般的數據接收函數來進行接收的。然而有時卻更喜歡使用一般的方式來接收這些越界數據。當選擇這種方法時,越界數據做爲一般數據流的一部分在一般數據以前到達。

要使用這個特徵,咱們能夠用下面的代碼來完成:

 1 #define TRUE    1
 2 #define FALSE   0
 3 int z;
 4 int s;    
 5 int so_oobinline;
 6 ...
 7 so_oobinline = TRUE;
 8 z = setsockopt(s,
 9     SOL_SOCKET,
10     SO_OOBINLINE,
11     &so_oobinline,
12     sizeof so_oobinline);
13 if ( z )
14     perror("setsockopt(2)");

 

在設置了SO_OOBINLINE選項以後,越界數據就會與一般數據一塊兒接收。在這種方式下,所接收的越界數據與一般數據相同。

SO_PASSCRED與SO_PEERCRED選項 這些選項僅適用於PF_UNIX(PF_LOCAL)套接口。這些選項用來在當前主機的本地套接口上控制與傳遞憑證。這也許是最難掌握的一個主題。就如今而言,咱們只須要簡單的注意到,若是咱們但願編寫服務本地主機客戶的服務程序時,咱們也許會對這兩個選項感興趣。

相關文章
相關標籤/搜索