套介面選項(轉)

post0發表於2007-08-11
套介面選項(轉)[@more@]

獲取和設定影響套介面選項的函式:

getsockopt :獲取套介面選項 setsockopt: 獲取套介面選項 fcntl: 設定套介面為非阻塞I/O型訊號驅動I/O型等 oictl 套介面選項 SO-KEEPALIVE SO-LINGER SE-RCVBUF 和 SO-SNDBUF SO-RCVWAT和 SO-SNDLOWAT SO-RCVTIMEO和 SO-SNDTIMEO SO-REUSEADDR和 SO-REUSPORT IP-TTL TCP-KEEPALIVE

--------------------------------------------------------------------------------

getsockopt 和 setsockopt

獲得套介面選項: int getsockopt ( int sockfd, int level, int optname, void * optval, socklen_t *opteln ) 設定套介面選項: int setsockopt ( int sockfd, int level, int optname, const void * optval, socklen_t *opteln ) sockfd(套接字): 指向一個開啟的套介面描述字 level:(級別): 指定選項程式碼的型別。 SOL_SOCKET: 基本套介面 IPPROTO_IP: IPv4套介面 IPPROTO_IPV6: IPv6套介面 IPPROTO_TCP: TCP套介面 optname(選項名): 選項名稱 optval(選項值): 是一個指向變數的指標 型別:整形,套介面結構,其他結構型別:linger{}, timeval{ } optlen(選項長度) :optval 的大小返回值:標誌開啟或關閉某個特徵的二進位制選項

--------------------------------------------------------------------------------

檢查套介面選項的程式

輸出套介面的選項: 定義感興趣的套介面選項 呼叫getsockopt 輸出套介面選項 定義聯合:不同的套介面選項有不同型別

union val { //套介面選項可能有的5個型別分別作為一個成員: int i_val; long l_val; char c_val[10]; struct linger linger_val; struct timeval timeval_val; //struct {int S; int uS} } val;

//函式原型(prototype),這些函式用於輸出套介面選項的值 static char *sock_str_flag(union val *, int); //靜態函式,只可在本檔案中被呼叫 static char *sock_str_int(union val *, int); static char *sock_str_linger(union val *, int); static char *sock_str_timeval(union val *, int); //定義結構sock_opts, 其中包含了獲得或輸出套介面選項的所有資訊 struct sock_opts { char *opt_str; //字元名稱 int opt_level; //級別 int opt_name; //名稱 char *(*opt_val_str)(union val *, int); //函式指標,用於輸出, }

//定義結構陣列並初始化 struct sock_opts sock_opts[ ] = { //全域性變數陣列才可以初始化 "SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, sock_str_flag, "SO_DEBUG", SOL_SOCKET, SO_DEBUG, sock_str_flag, #ifdef SO_REUSEPORT //編譯時用的宏定義 "SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, sock_str_flag, #else //沒有這個選項 "SO_REUSEPORT", 0, 0, NULL, //NULL表示沒有定義 #endif "SO_TYPE", SOL_SOCKET, SO_TYPE, sock_str_int, "IP_TTL", IPPROTO_IP, IP_TTL, sock_str_int, "TCP_MAXSEG", IPPROTO_TCP,TCP_MAXSEG, sock_str_int, NULL, { /*結束標誌 */} 0, 0, NULL }; 源程式: int main(int argc, char **argv) { int fd, len; struct sock_opts *ptr; //結構型別 fd = Socket(AF_INET, SOCK_STREAM, 0); //獲得套接字 for (ptr = sock_opts; ptr->opt_str != NULL; ptr++) { //從第一個選項到最後一個 printf(“%s: ”, ptr->opt_str); //輸出字元名 if (ptr->opt_val_str == NULL) //沒有定義的情況 printf("(undefined) "); else { len = sizeof(val); //獲得套介面選項 if (getsockopt(fd, ptr->opt_level, ptr->opt_name, val, len) == -1) { //返回值為1,函式呼叫失敗 err_ret("getsockopt error");} //輸出選項的預設值 else printf("default = %s ", (*ptr->opt_val_str)(&val, len)); } } //End of for loop exit(0); }

static char strres[128]; //靜態變數,在函式呼叫後保留原值 static char * sock_str_flag(union val *ptr, int len) { if (len != sizeof(int)) //長度不相符 snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len); else //轉換字串 snprintf(strres, sizeof(strres),"%s", (ptr->i_val == 0) ? "off" : "on"); return(strres); }

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

基本套介面選項

SO_KEEPALIVE

檢測對方主機是否崩潰,避免(伺服器)永遠阻塞於TCP連線的輸入。 設定該選項後,如果2小時內在此套介面的任一方向都沒有資料交換,TCP就自動給對方 發一個保持存活探測分節(keepalive probe)。這是一個對方必須響應的TCP分節.它會導

致以下三種情況: 對方接收一切正常:以期望的ACK響應。2小時後,TCP將發出另一個探測分節。對方已崩潰且已重新啟動:以RST響應。套介面的待處理錯誤被置為ECONNRESET,套接 口本身則被關閉。對方無任何響應:源自berkeley的TCP傳送另外8個探測分節,相隔75秒一個,試圖得到一個響應。在發出第一個探測分節11分鐘15秒後若仍無響應就放棄。套介面的待處理錯誤被置為ETIMEOUT,套介面本身則被關閉。如ICMP錯誤是“host unreachable(主機不可達)”,說明對方主機並沒有崩潰,但是不可達,這種情況下待處理錯誤被置為 EHOSTUNREACH。

SO_RCVBUF和SO_SNDBUF

每個套介面都有一個傳送緩衝區和一個接收緩衝區。 接收緩衝區被TCP和UDP用來將接收到的資料一直儲存到由應用程式來讀。 TCP:TCP通告另一端的視窗大小。 TCP套介面接收緩衝區不可能溢位,因為對方不允許發出超過所通告視窗大小的資料。這就是TCP的流量控制,如果對方無視視窗大小而發出了超過宙口大小的資料,則接 收方TCP將丟棄它。 UDP:當接收到的資料包裝不進套介面接收緩衝區時,此資料包就被丟棄。UDP是沒有流量控制的;快的傳送者可以很容易地就淹沒慢的接收者,導致接收方的UDP丟棄資料包。

SO_LINGER 指定函式CLOSE對面相連線的協議如何操作——當由資料殘留在套介面傳送緩衝區時的處理 LINGER結構 struct linger { int l_onoff; // 0=off, nonzero=on int l_linger; //linger time in seconds };

SO_RCVLOWAT 和SO_SNDLOWAT

每個套介面都有一個接收低潮限度和一個傳送低潮限度。它們是函式selectt使用的,接收低潮限度是讓select返回“可讀”而在套介面接收緩衝區中必須有的資料總量。 ——對於一個TCP或UDP套介面,此值預設為1。傳送低潮限度是讓select返回“可寫” 而在套介面傳送緩衝區中必須有的可用空間。對於TCP套介面,此值常預設為2048。 對於UDP使用低潮限度,由於其傳送緩衝區中可用空間的位元組數是從不變化的,只要 UDP套介面傳送緩衝區大小大於套介面的低潮限度,這樣的UDP套介面就總是可寫的。 UDP沒有傳送緩衝區,只有傳送緩衝區的大小。

--------------------------------------------------------------------------------

TCP 套介面選項

TCP_KEEPALIVE

指定TCP開始傳送保持存活探測分節前以秒為單位的連線空閒時間。預設值至少必須

為7200秒,即2小時。此選項僅在SO_KEPALIVEE套介面選項開啟時才有效。

TCP_MAXSEG

獲取或設定TCP連線的最大分節大小(MSS)。返回值是我們的TCP傳送給另一端的最大資料量,它常常就是由另一端用SYN分節通告的MSS,除非我們的TCP選擇使用一個比對方通告的MSS小些的值。如果此值在套介面連線之前取得,則返回值為未從另·—端收到Mss選項的情況下所用的預設值。小於此返回值的信可能真正用在連線上,因為譬如說使用時間戳選項的話,它在每個分節上佔用12位元組的TCP選項容量。我們的TcP將傳送的每個分節的最大資料量也可在連線存活期內改變,但前提是TCP要支援路徑MTU 發現功能。如果到對方的路徑改變了,此值可上下調整。

--------------------------------------------------------------------------------

例程式:

//獲得傳送緩衝區大小和MSS大小,設定傳送緩衝區大小

//獲得傳送緩衝區大小和MSS大小 #include "unp.h" #include /* for TCP_MAXSEG */ int main(int argc, char **argv) { int sockfd, rcvbuf, mss; socklen_t len; struct sockaddr_in servaddr; if (argc != 2) err_quit("usage: rcvbuf "); sockfd = Socket(AF_INET, SOCK_STREAM, 0); len = sizeof(rcvbuf); Getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, rcvbuf, len); len = sizeof(mss); Getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len); printf("defaults: SO_RCVBUF = %d, MSS = %d ", rcvbuf, mss); bzero(servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(13); /* daytime server */ Inet_pton(AF_INET, argv[1], servaddr.sin_addr); Connect(sockfd, (SA *) &servaddr, sizeof(servaddr)); len = sizeof(rcvbuf); Getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &len); len = sizeof(mss); Getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len); printf("after connect: SO_RCVBUF = %d, MSS = %d ", rcvbuf, mss); exit(0); }

//設定傳送緩衝區大小 #include "unp.h" #include /* for TCP_MAXSEG value */ int main(int argc, char **argv) { int sockfd, mss, sendbuff; socklen_t optlen; float kk; sockfd = Socket(AF_INET, SOCK_STREAM, 0); /* Fetch and print the TCP maximum segment size. */ optlen = sizeof(mss); sendbuff =2048; Setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, sendbuff, sizeof(sendbuff)); optlen = sizeof(sendbuff); Getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, sendbuff, &optlen); printf("After send buffer size = %d ", sendbuff); exit(0);

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-944698/,如需轉載,請註明出處,否則將追究法律責任。

相關文章