NetWork

最近在新的平臺上測試程序,之前一些沒有注意到的問題都成爲了性能瓶頸,經過設置一些TCP/IP選項可以解決一部分問題,固然根本的解決方法是重構代碼,從新設計服務器框架。先列出幾個TCP/IP選項:
選項
man 7 socket:
SO_REUSEADDR
SO_RECVBUF/SO_SNDBUF
SO_KEEPALIVE
SO_LINGER
man 7 tcp:
TCP_CORK
TCP_NODELAY
TCP_DEFER_ACCEPT
TCP_KEEPCNT/TCP_KEEPIDLE/TCP_KEEPINTVL
SO_REUSEADDRphp

man 命令的 領域 名稱 說明
1 用戶命令, 可由任何人啓動的。
2 系統調用, 即由內核提供的函數。
3 例程, 即庫函數。
4 設備, 即/dev目錄下的特殊文件。
5 文件格式描述, 例如/etc/passwd。
6 遊戲, 不用解釋啦!
7 雜項, 例如宏命令包、慣例等。
8 系統管理員工具, 只能由root啓動。
9 其餘(Linux特定的), 用來存放內核例行程序的文檔。html

SO_REUSEADDR選項:node

在服務器程序中,SO_REUSEADDR socket選項一般在調用bind()以前被設置。
SO_REUSEADDR能夠用在如下四種狀況下: 
(摘自《Unix網絡編程》卷一,即UNPv1)
一、當有一個有相同本地地址和端口的socket1處於TIME_WAIT狀態時,而你啓動的程序的socket2要佔用該地址和端口,你的程序就要用到該選項。 
二、SO_REUSEADDR容許同一port上啓動同一服務器的多個實例(多個進程)。但每一個實例綁定的IP地址是不能相同的在有多塊網卡或用IP Alias技術的機器能夠測試這種狀況。 
三、SO_REUSEADDR容許單個進程綁定相同的端口到多個socket上,但每一個socket綁定的ip地址不一樣。這和2很類似,區別請看UNPv1。 
四、SO_REUSEADDR容許徹底相同的地址和端口的重複綁定。但這隻用於UDP的多播,不用於TCPlinux

TCP_NODELAY/TCP_CHORK選項:
TCP_NODELAY/TCP_CHORK
TCP_NODELAY和TCP_CORK基本上控制了包的「Nagle化」,Nagle化在這裏的含義是採用Nagle算法把較小的包組裝爲更大的幀。TCP_NODELAY和TCP_CORK都禁掉了Nagle算法,只不過他們的行爲不一樣而已。
TCP_NODELAY 不使用Nagle算法,不會將小包進行拼接成大包再進行發送,直接將小包發送出去,會使得小包時候用戶體驗很是好。算法

Nagle算法參見本身的博客:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201231214038740/
當在傳送大量數據的時候,爲了提升TCP發送效率,能夠設置TCP_CORK,CORK顧名思義,就是"塞子"的意思,它會盡可能在每次發送最大的數據量。當設置了TCP_CORK後,會有阻塞200ms,當阻塞時間事後,數據就會自動傳送。
詳細的資料能夠查看參考文獻5。編程

SO_LINGER選項:
SO_LINGER
linger,顧名思義是延遲延緩的意思,這裏是延緩面向鏈接的socket的close操做。服務器

默認,close當即返回,可是當發送緩衝區中還有一部分數據的時候,系統將會嘗試將數據發送給對端。SO_LINGER能夠改變close的行爲。網絡

控制SO_LINGER經過下面一個結構:
struct linger
{
      int l_onoff; /*0=off, nonzero=on*/
      int l_linger; /*linger time, POSIX specifies units as seconds*/
};
經過結構體中成員的不一樣賦值,能夠表現爲下面幾種狀況:
1. l_onoff設置爲0,選項被關閉。l_linger值被忽略,就是上面的默認情形,close當即返回。
2. l_onoff設置爲非0,l_linger被設置爲0,則close()不被阻塞當即執行,丟棄socket發送緩衝區中的數據,並向對端發送一個RST報文。併發

    這種關閉方式稱爲「強制」或「失效」關閉。
3. l_onoff設置爲非0,l_linger被設置爲非0,則close()調用阻塞進程,直到所剩數據發送完畢或超時。框架

    這種關閉稱爲「優雅的」關閉。
注意:
       這個選項須要謹慎使用,尤爲是強制式關閉,會丟失服務器發給客戶端的最後一部分數據。UNP中:
The TIME_WAIT state is our friend and is there to help us(i.e., to let the old duplicate segments expire in the network).

 

TCP_DEFER_ACCEPT選項:
TCP_DEFER_ACCEPT
defer accept,從字面上理解是推遲accept,其實是當接收到第一個數據以後,纔會建立鏈接,三次握手完成,鏈接尚未創建

對於像HTTP等非交互式的服務器,這個頗有意義,能夠用來防護空鏈接攻擊(只是創建鏈接,可是不發送任何數據)。
使用方法以下:

 

val = 5;
setsockopt(srv_socket->fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val)) ;

 

裏面 val 的單位是秒,注意若是打開這個功能,kernel 在 val 秒以內尚未收到數據,不會繼續喚醒進程,而是直接丟棄鏈接。若是服務器設置TCP_DEFER_ACCEPT選項後,服務器受到一個CONNECT請求後,三次握手以後,新的socket狀態依然爲SYN_RECV,而不是ESTABLISHED,操做系統不會Accept
因爲設置TCP_DEFER_ACCEPT選項以後,三次握手後狀態沒有達到ESTABLISHED,而是SYN_RECV。這個時候,若是客戶端一直沒有發送"數據"報文,服務器將重傳SYN/ACK報文,重傳次數受net.ipv4.tcp_synack_retries參數控制,達到重傳次數以後,纔會再次進行setsockopt中設置的超時值,所以會出現SYN_RECV生存時間比設置值大一些的狀況。
關於SYN_RECV狀態能夠查看參考文獻7。

 

SO_KEEPALIVE選項:
SO_KEEPALIVE/TCP_KEEPCNT/TCP_KEEPIDLE/TCP_KEEPINTVL
        若是一方已經關閉或異常終止鏈接,而另外一方殊不知道,咱們將這樣的TCP鏈接稱爲半打開的。

        TCP經過保活定時器(KeepAlive)來檢測半打開鏈接。
         在高併發的網絡服務器中,常常會出現漏掉socket的狀況,對應的結果有一種狀況就是出現大量的CLOSE_WAIT狀態的鏈接。這個時候,能夠經過設置KEEPALIVE選項來解決這個問題,固然還有其餘的方法能夠解決這個問題,詳細的狀況能夠查看參考資料8。
使用方法以下:

 

//Setting For KeepAlive
int keepalive = 1;
setsockopt(incomingsock,SOL_SOCKET,SO_KEEPALIVE,(void*)(&keepalive),(socklen_t)sizeof(keepalive));
int keepalive_time = 30;
setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPIDLE,(void*)(&keepalive_time),(socklen_t)sizeof(keepalive_time));
int keepalive_intvl = 3;
setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPINTVL,(void*)(&keepalive_intvl),(socklen_t)sizeof(keepalive_intvl));
int keepalive_probes= 3;
setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPCNT,(void*)(&keepalive_probes),(socklen_t)sizeof(keepalive_probes));

 


       設置SO_KEEPALIVE選項來開啓KEEPALIVE,而後經過TCP_KEEPIDLE、TCP_KEEPINTVL和TCP_KEEPCNT設置keepalive的開始時間、間隔、次數等參數。
        固然,也能夠經過設置/proc/sys/net/ipv4/tcp_keepalive_time、tcp_keepalive_intvl和tcp_keepalive_probes等內核參數來達到目的,可是這樣的話,會影響全部的socket,所以建議使用setsockopt設置。參考:1. man 7 socket2. man 7 tcp3. 《Unix Network Programming》 Section 7.5 "Generic Socket Options"4. http://www.linuxsir.org/bbs/showthread.php?t=557385. http://blog.chinaunix.net/u/12592/showart_1723934.html6. http://blog.csdn.net/fullsail/archive/2009/08/09/4429102.aspx7. http://www.kernelchina.org/?q=node/1108. http://blog.chinaunix.net/u/12592/showart.php?id=2059174

相關文章
相關標籤/搜索