int setsockopt(
SOCKET s,
int level,
int optname,
const char* optval,
int optlen
);算法
s(套接字): 指向一個打開的套接口描寫敘述字
level:(級別): 指定選項代碼的類型。
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname(選項名): 選項名稱
optval(選項值): 是一個指向變量的指針 類型:整形,套接口結構, 其它結構類型:linger{}, timeval{ }
optlen(選項長度) :optval 的大小安全
返回值:標誌打開或關閉某個特徵的二進制選項
[/code:1:59df4ce128]網絡
========================================================================
SOL_SOCKET
------------------------------------------------------------------------
SO_BROADCAST 贊成發送廣播數據 int
適用於 UDP socket。其意義是贊成 UDP socket 「廣播」(broadcast)訊息到網路上。數據結構
SO_DEBUG 贊成調試 int異步
SO_DONTROUTE 不查找路由 intsocket
SO_ERROR 得到套接字錯誤 intide
SO_KEEPALIVE 保持鏈接 int
檢 測對方主機是否崩潰,避免(server)永遠堵塞於TCP鏈接的輸入。 設置該選項後,假設2小時內在此套接口的任一方向都沒有數據交換,TCP就本身主動給對方 發一個保持存活探測分節(keepalive probe)。這是一個對方必須響應的TCP分節.它會致使下面三種狀況: 對方接收一切正常:以指望的 ACK響應。2小時後,TCP將發出還有一個探測分節。 對方已崩潰且已又一次啓動:以RST響應。套接口的待處理錯誤被置爲ECONNRESET,套接 口自己則被關閉。 對方無不論什麼響應:源自berkeley的TCP發送另外8個探測分節,相隔75秒一個,試圖獲得 一個響應。在發出第一個探測分節11分鐘15秒後若仍無響應就放棄。套接口的待處理錯 誤被置爲ETIMEOUT,套接口自己則被關閉。如ICMP錯誤是「host unreachable (主機不 可達)」,說明對方主機並無崩潰,但是不可達,這樣的狀況下待處理錯誤被置爲 EHOSTUNREACH。函數
SO_DONTLINGER 若爲真,則SO_LINGER選項被禁止。
SO_LINGER 延遲關閉鏈接 struct linger
上面這兩個選項影響close行爲
選項 間隔 關閉方式 等待關閉與否
SO_DONTLINGER 不關心 優雅 否
SO_LINGER 零 強制 否
SO_LINGER 非零 優雅 是
若 設置了SO_LINGER(亦即linger結構中的l_onoff域設爲非零,參見2.4,4.1.7和4.1.21各節),並設置了零超時間隔,則 closesocket()不被堵塞立刻運行,不管是否有排隊數據未發送或未被確認。這樣的關閉方式稱爲「強制」或「失效」關閉,因爲套接口的虛電路立刻被 復位,且丟失了未發送的數據。在遠端的recv()調用將以WSAECONNRESET出錯。
若設置了SO_LINGER並肯定了非零的超時間 隔,則closesocket()調用堵塞進程,直到所剩數據發送完成或超時。這樣的關閉稱爲「優雅的」關閉。請注意假設套接口置爲非堵塞且 SO_LINGER設爲非零超時,則closesocket()調用將以WSAEWOULDBLOCK錯誤返回。
若在一個流類套接口上設置了 SO_DONTLINGER(也就是說將linger結構的l_onoff域設爲零;參見2.4,4.1.7,4.1.21節),則 closesocket()調用立刻返回。但是,假設可能,排隊的數據將在套接口關閉前發送。請注意,在這樣的狀況下WINDOWS套接口實現將在一段不確 定的時間內保留套接口以及其它資源,這對於想用因此套接口的應用程序來講有必定影響。性能
SO_OOBINLINE 帶外數據放入正常數據流,在普通數據流中接收帶外數據 int大數據
SO_RCVBUF 接收緩衝區大小 int
設置接收緩衝區的保留大小
與 SO_MAX_MSG_SIZE 或TCP滑動窗體無關,假設通常發送的包很是大很是頻繁,那麼使用這個選項
SO_SNDBUF 發送緩衝區大小 int
設置發送緩衝區的保留大小
與 SO_MAX_MSG_SIZE 或TCP滑動窗體無關,假設通常發送的包很是大很是頻繁,那麼使用這個選項
每 個套接口都有一個發送緩衝區和一個接收緩衝區。 接收緩衝區被TCP和UDP用來將接收到的數據一直保存到由應用進程來讀。 TCP:TCP通告還有一端的窗體大小。 TCP套接口接收緩衝區不可能溢出,因爲對方不一樣意發出超過所通告窗體大小的數據。 這就是TCP的流量控制,假設對方無視窗體大小而發出了超過宙口大小的數據,則接 收方TCP將丟棄它。 UDP:當接收到的數據報裝不進套接口接收緩衝區時,此數據報就被丟棄。UDP是沒有 流量控制的;快的發送者可以很是easy地就淹沒慢的接收者,致使接收方的UDP丟棄數據報。
SO_RCVLOWAT 接收緩衝區下限 int
SO_SNDLOWAT 發送緩衝區下限 int
每 個套接口都有一個接收低潮限度和一個發送低潮限度。它們是函數selectt使用的, 接收低潮限度是讓select返回「可讀」而在套接口接收緩衝區中必須有的數據總量。 ——對於一個TCP或UDP套接口,此值缺省爲1。發送低潮限度是讓select返回「可寫」 而在套接口發送緩衝區中必須有的可用空間。對於TCP套接口,此值常缺省爲2048。 對於UDP使用低潮限度, 由於其發送緩衝區中可用空間的字節數是從不變化的,僅僅要 UDP套接口發送緩衝區大小大於套接口的低潮限度,這種UDP套接口就老是可寫的。 UDP沒有發送緩衝區,僅僅有發送緩衝區的大小。
SO_RCVTIMEO 接收超時 struct timeval
SO_SNDTIMEO 發送超時 struct timeval
SO_REUSERADDR 贊成重用本地地址和port int
充許綁定已被使用的地址(或port號),可以參考bind的man
SO_EXCLUSIVEADDRUSE
獨佔模式使用port,就是不充許和其餘程序使用SO_REUSEADDR共享的使用某一port。
在肯定多重綁定使用誰的時候,依據一條原則是誰的指定最明白則將包遞交給誰,而且沒有權限之分,也就是說低級權限的用戶是可以重綁定在高級權限如服務啓動的port上的,這是很重大的一個安全隱患,
假設不想讓本身程序被監聽,那麼使用這個選項
SO_TYPE 得到套接字類型 int
SO_BSDCOMPAT 與BSD系統兼容 int
==========================================================================
IPPROTO_IP
--------------------------------------------------------------------------
IP_HDRINCL 在數據包中包括IP首部 int
這個選項常用於***技術中,隱藏本身的IP地址
IP_OPTINOS IP首部選項 int
IP_TOS 服務類型
IP_TTL 生存時間 int
下面IPV4選項用於組播
IPv4 選項 數據類型 描 述
IP_ADD_MEMBERSHIP struct ip_mreq 添�到組播組中
IP_ROP_MEMBERSHIP struct ip_mreq 從組播組中退出
IP_MULTICAST_IF struct ip_mreq 指定提交組播報文的接口
IP_MULTICAST_TTL u_char 指定提交組播報文的TTL
IP_MULTICAST_LOOP u_char 使組播報文環路有效或無效
在頭文件裏定義了ip_mreq結構:
[code:1:63724de67f]
struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
[/code:1:63724de67f]
若進程要添�到一個組播組中,用soket的setsockopt()函數發送該選項。該選項類型是ip_mreq結構,它的第一個字段imr_multiaddr指定了組播組的地址,第二個字段imr_interface指定了接口的IPv4地址。
IP_DROP_MEMBERSHIP
該選項用來從某個組播組中退出。數據結構ip_mreq的用法與上面一樣。
IP_MULTICAST_IF
該選項可以改動網絡接口,在結構ip_mreq中定義新的接口。
IP_MULTICAST_TTL
設置組播報文的數據包的TTL(生存時間)。默認值是1,表示數據包僅僅能在本地的子網中傳送。
IP_MULTICAST_LOOP
組播組中的成員本身也會收到它向本組發送的報文。這個選項用於選擇是否激活這樣的狀態。
無雙 回覆於:2003-05-08 21:21:52
IPPRO_TCP
--------------------------------------------------------------------------
TCP_MAXSEG TCP最大數據段的大小 int
獲 取或設置TCP鏈接的最大分節大小(MSS)。返回值是咱們的TCP發送給還有一端的最大 數據量,它常常就是由還有一端用SYN分節通告的MSS,除非咱們的TCP選擇使用一個比 對方通告的MSS小些的值。假設此值在套接口鏈接以前取得,則返回值爲未從另·—端 收到Mss選項的狀況下所用的缺省值。小於此返回值的信可能真正用在鏈接上,因爲譬 如說使用時間戳選項的話,它在每個分節上佔用12字節的TCP選項容量。咱們的TcP將 發送的每個分節的最大數據量也可在鏈接存活期內改變,但前提是TCP要支持路徑MTU 發現功能。假設到對方的路徑改變了,此值可上下調整。
TCP_NODELAY 不使用Nagle算法 int
指定TCP開始發送保持存活探測分節前以秒爲單位的鏈接空暇時間。缺省值至少必須爲7200秒,即2小時。此選項僅在SO_KEPALIVEE套接口選項打開時纔有效。
TCP_NODELAY 和 TCP_CORK,
這 兩個選項都對網絡鏈接的行爲具備關鍵的數據。不少UNIX系統都實現了TCP_NODELAY選項,但是,TCP_CORK則是Linux系統所獨有的而 且相對較新;它首先在內核版本號2.4上得以實現。此外,其它UNIX系統版本號也有功能類似的選項,值得注意的是,在某種由BSD派生的系統上的 TCP_NOPUSH選項事實上就是TCP_CORK的一部分詳細實現。
TCP_NODELAY和TCP_CORK基本上控制了包的 「Nagle化」,Nagle化在這裏的含義是採用Nagle算法把較小的包組裝爲更大的幀。John Nagle是Nagle算法的發明人,後者就是用他的名字來命名的,他在1984年首次用這樣的方法來嘗試解決福特汽車公司的網絡擁塞問題(欲瞭解詳情請參 看IETF RFC 896)。他解決的問題就是所謂的silly window syndrome ,中文稱「愚蠢窗體症候羣」,詳細含義是,因爲廣泛終端應用程序每產生一次擊鍵操做就會發送一個包,而典型狀況下一個包會擁有一個字節的數據載荷以及40 個字節長的包頭,因而產生4000%的過載,很是輕易地就能令網絡發生擁塞,。 Nagle化後來成了一種標準而且立刻在因特網上得以實現。它現在已經成爲缺省配置了,但在咱們看來,有些場合下把這一選項關掉也是合乎需要的。
現 在讓咱們假設某個應用程序發出了一個請求,但願發送小塊數據。咱們可以選擇立刻發送數據或者等待產生不少其它的數據而後再一次發送兩種策略。假設咱們立刻發送 數據,那麼交互性的以及客戶/server型的應用程序將極大地受益。好比,當咱們正在發送一個較短的請求而且等候較大的響應時,相關過載與傳輸的數據總量相比 就會比較低,而且,假設請求立刻發出那麼響應時間也會快一些。以上操做可以經過設置套接字的TCP_NODELAY選項來完畢,這樣就禁用了Nagle算 法。
第二種狀況則需要咱們等到數據量達到最大時才經過網絡一次發送全部數據,這樣的傳輸數據方式故意於大量數據的通訊性能,典型的應用就是文件服 務器。應用 Nagle算法在這樣的狀況下就會產生問題。但是,假設你正在發送大量數據,你可以設置TCP_CORK選項禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。如下就讓咱們細緻分析下其工做原理。
假設應用程序 使用sendfile()函數來轉移大量數據。應用協議一般要求發送某些信息來預先解釋數據,這些信息事實上就是報頭內容。典型狀況下報頭很是小,而且套接字 上設置了TCP_NODELAY。有報頭的包將被立刻傳輸,在某些狀況下(取決於內部的包計數器),因爲這個包成功地被對方收到後需要請求對方確認。這 樣,大量數據的傳輸就會被推遲而且產生了沒必要要的網絡流量交換。
但是,假設咱們在套接字上設置了TCP_CORK(可以比喻爲在管道上插入 「塞子」)選項,具備報頭的包就會填補大量的數據,全部的數據都依據大小本身主動地經過包傳輸出去。當傳輸數據完畢時,最好取消TCP_CORK 選項設置給鏈接「拔去塞子」以便任一部分的幀都能發送出去。這同「塞住」網絡鏈接同等重要。
總而言之,假設你確定能一塊兒發送多個數據集合(好比HTTP響應的頭和正文),那麼咱們建議你設置TCP_CORK選項,這樣在這些數據之間不存在延遲。能極大地故意於WWW、FTP以及文件server的性能,同一時候也簡化了你的工做。演示樣例代碼例如如下:
intfd, on = 1;
…
/* 此處是建立套接字等操做,出於篇幅的考慮省略*/
…
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* cork */
write (fd, …);
fprintf (fd, …);
sendfile (fd, …);
write (fd, …);
sendfile (fd, …);
…
on = 0;
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* 拔去塞子 */
不幸的是,不少常用的程序並無考慮到以上問題。好比,Eric Allman編寫的sendmail就沒有對其套接字設置不論什麼選項。
Apache HTTPD 是因特網上最流行的Webserver,它的全部套接字就都設置了TCP_NODELAY選項,而且其性能也深受大多數用戶的愜意。這是爲何呢?答案就在於實 現的區別之上。由BSD衍生的TCP/IP協議棧(值得注意的是FreeBSD)在這樣的情況下的操做就不一樣。當在TCP_NODELAY 模式下提交大量小數據塊傳輸時,大量信息將依照一次write()函數調用發送一塊數據的方式發送出去。然而,因爲負責請求交付確認的記數器是面向字節而 非面向包(在 Linux上)的,因此引入延遲的機率就減小了很是多。結果只和全部數據的大小有關係。而 Linux 在第一包到達以後就要求確認,FreeBSD則在進行如此操做以前會等待好幾百個包。
在Linux系統上,TCP_NODELAY的效果同習慣於BSD TCP/IP協議棧的開發人員所指望的效果有很是大不一樣,而且在Linux上的Apache性能表現也會更差些。其它在Linux上頻繁採用TCP_NODELAY的應用程序也有相同的問題。
TCP_DEFER_ACCEPT
我 們首先考慮的第1個選項是TCP_DEFER_ACCEPT(這是Linux系統上的叫法,其它一些操做系統上也有相同的選項但使用不一樣的名字)。爲了理 解TCP_DEFER_ACCEPT選項的詳細思想,咱們有必要大體闡述一下典型的HTTP客戶/server交互過程。請回憶下TCP是怎樣與數據傳輸的目標 創建鏈接的。在網絡上,在分離的單元之間傳輸的信息稱爲IP包(或IP 數據報)。一個包總有一個攜帶服務信息的包頭,包頭用於內部協議的處理,而且它也可以攜帶數據負載。服務信息的典型樣例就是一套所謂的標誌,它把包標記代 表TCP/IP協議棧內的特殊含義,好比收到包的成功確認等等。一般,在通過「標記」的包裏攜帶負載是全然可能的,但有時,內部邏輯迫使TCP/IP協議 棧發出僅僅有包頭的IP包。這些包經常會引起討厭的網絡延遲而且還添加�了系統的負載,結果致使網絡性能在整體上減小。
現在server建立了一個套接字同 時等待鏈接。TCP/IP式的鏈接過程就是所謂「3次握手」。首先,客戶程序發送一個設置SYN標誌而且不帶數據負載的TCP包(一個SYN包)。server 則以發出帶SYN/ACK標誌的數據包(一個SYN/ACK包)做爲剛纔收到包的確認響應。客戶隨後發送一個ACK包確認收到了第2個包從而結束鏈接過 程。在收到客戶發來的這個SYN/ACK包以後,server會喚醒一個接收進程等待數據到達。當3次握手完畢後,客戶程序即開始把「實用的」的數據發送給服務 器。一般,一個HTTP請求的量是很是小的而且全然可以裝到一個包裏。但是,在以上的狀況下,至少有4個包將用來進行雙向傳輸,這樣就添加�了可觀的延遲時 間。此外,你還得注意到,在「實用的」數據被髮送以前,接收方已經開始在等待信息了。
爲了減輕這些問題所帶來的影響,Linux(以及其它的一些 操做系統)在其TCP實現中包含了TCP_DEFER_ACCEPT選項。它們設置在偵聽套接字的server方,該選項命令內核不等待最後的ACK包而且在第 1個真正有數據的包到達才初始化偵聽進程。在發送SYN/ACK包以後,server就會等待客戶程序發送含數據的IP包。現在,僅僅需要在網絡上傳送3個包了, 而且還顯著減小了鏈接創建的延遲,對HTTP通訊而言尤爲如此。
這一選項在好些操做系統上都有對應的對等物。好比,在FreeBSD上,相同的行爲可以用下面代碼實現:
/* 爲明晰起見,此處略去無關代碼 */
struct accept_filter_arg af = { "dataready", "" };
setsockopt(s, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af));
這 個特徵在FreeBSD上叫作「接受過濾器」,而且具備多種使用方法。只是,在差點兒所有的狀況下其效果與TCP_DEFER_ACCEPT是同樣的:server不 等待最後的ACK包而只等待攜帶數據負載的包。要了解該選項及其對高性能Webserver的重要意義的不少其它信息請參考Apache文檔上的有關內容。
就HTTP 客戶/server交互而言,有可能需要改變客戶程序的行爲。客戶程序爲何要發送這樣的「沒用的」ACK包呢?這是因爲,TCP協議棧沒法知道ACK包的狀態。 假設採用FTP而非HTTP,那麼客戶程序直到接收了FTPserver提示的數據包以後才發送數據。在這樣的狀況下,延遲的ACK將致使客戶/server交互出現延 遲。爲了肯定ACK是否必要,客戶程序必須知道應用程序協議及其當前狀態。這樣,改動客戶行爲就成爲必要了。
對Linux客戶程序來講,咱們還可 以採用還有一個選項,它也被叫作TCP_DEFER_ACCEPT。咱們知道,套接字分紅兩種類型,偵聽套接字和鏈接套接字,因此它們也各自具備對應的 TCP選項集合。所以,經常同一時候採用的這兩類選項卻具備相同的名字也是全然可能的。在鏈接套接字上設置該選項之後,客戶在收到一個SYN/ACK包以後就 再也不發送ACK包,而是等待用戶程序的下一個發送數據請求;所以,server發送的包也就對應下降了。
TCP_QUICKACK
阻 止因發送無用包而引起延遲的還有一個方法是使用TCP_QUICKACK選項。這一選項與 TCP_DEFER_ACCEPT不一樣,它不但能用做管理鏈接創建過程而且在正常傳輸數據過程期間也可以使用。另外,它能在客戶/server鏈接的不論什麼一方設 置。假設知道數據不久即將發送,那麼推遲ACK包的發送就會派上用場,而且最好在那個攜帶數據的數據包上設置ACK 標誌以便把網絡負載減到最小。當發送方確定數據將被立刻發送(多個包)時,TCP_QUICKACK 選項可以設置爲0。對處於「鏈接」狀態下的套接字該選項的缺省值是1,首次使用之後內核將把該選項立刻復位爲1(這是個一次性的選項)。
在某些情形下,發出ACK包則很是實用。ACK包將確認數據塊的接收,而且,當下一塊被處理時不至於引入延遲。這樣的傳輸數據模式對交互過程是至關典型的,因爲此類狀況下用戶的輸入時刻沒法預測。在Linux系統上這就是缺省的套接字行爲。
在 上述狀況下,客戶程序在向server發送HTTP請求,而預先就知道請求包很是短因此在鏈接創建以後就應該立刻發送,這可謂HTTP的典型工做方式。既然沒有必 要發送一個純粹的ACK包,因此設置TCP_QUICKACK爲0以提升性能是全然可能的。在server方,這兩種選項都僅僅能在偵聽套接字上設置一次。所有的 套接字,也就是被接受呼叫間接建立的套接字則會繼承原有套接字的所有選項。
經過TCP_CORK、TCP_DEFER_ACCEPT和 TCP_QUICKACK選項的組合,參與每一HTTP交互的數據包數量將被減小到最小的可接受水平(依據TCP協議的要求和安全方面的考慮)。結果不只 是得到更快的傳輸數據和請求處理速度而且還使客戶/server雙向延遲實現了最小化。
2、使用樣例說明
一下來源於互聯網: 1.closesocket(通常不會立刻關閉而經歷TIME_WAIT的過程)後想繼續重用該socket: 2. 假設要已經處於鏈接狀態的soket在調用closesocket後強制關閉,不經歷 3.在send(),recv()過程當中有時由於網絡情況等緣由,發收不能預期進行,而設置收發時限: 4.在send()的時候,返回的是實際發送出去的字節(同步)或發送到socket緩衝區的字節
9.假設在發送數據的過程當中(send()沒有完畢,還有數據沒發送)而調用了closesocket(),曾經咱們通常採取的措施是"從容關閉"shutdown(s,SD_BOTH),但是數據是確定丟失了,怎樣設置讓程序知足詳細應用的要求(即讓沒發完的數據發送出去後在關閉socket)?struct linger {u_short l_onoff;u_short l_linger;};linger m_sLinger;m_sLinger.l_onoff=1;//(在closesocket()調用,但是還有數據沒發送完畢的時候允許逗留)// 假設m_sLinger.l_onoff=0;則功能和2.)做用一樣;m_sLinger.l_linger=5;//(允許逗留的時間爲5秒)setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger)); |