導航:首頁 > 操作系統 > linuxlinger

linuxlinger

發布時間:2023-02-12 09:19:48

linux下怎麼設置tcp

Socket的send函數在執行時報EAGAIN的錯誤 當客戶通過Socket提供的send函數發送大的數據包時,就可能返回一個EGGAIN的錯誤。該錯誤產生的原因是由於send 函數中的size變數大小超過了tcp_sendspace的值。tcp_sendspace定義了應用在調用send之前能夠在kernel中緩存的數據量。當應用程序在socket中設置了O_NDELAY或者O_NONBLOCK屬性後,如果發送緩存被占滿,send就會返回EAGAIN的錯誤。 為了消除該錯誤,有三種方法可以選擇: 1.調大tcp_sendspace,使之大於send中的size參數 ---no -p -o tcp_sendspace=65536 2.在調用send前,在setsockopt函數中為SNDBUF設置更大的值 3.使用write替代send,因為write沒有設置O_NDELAY或者O_NONBLOCK 1. tcp 收發緩沖區默認值 [root@qljt core]# cat /proc/sys/net/ipv4/tcp_rmem 4096 87380 4161536 87380 :tcp接收緩沖區的默認值 [root@qljt core]# cat /proc/sys/net/ipv4/tcp_wmem 4096 16384 4161536 16384 : tcp 發送緩沖區的默認值 2. tcp 或udp收發緩沖區最大值 [root@qljt core]# cat /proc/sys/net/core/rmem_max 131071 131071:tcp 或 udp 接收緩沖區最大可設置值的一半。 也就是說調用 setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 時rcv_size 如果超過 131071,那麼 getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 去到的值就等於 131071 * 2 = 262142 [root@qljt core]# cat /proc/sys/net/core/wmem_max 131071 131071:tcp 或 udp 發送緩沖區最大可設置值得一半。 跟上面同一個道理 3. udp收發緩沖區默認值 [root@qljt core]# cat /proc/sys/net/core/rmem_default 111616:udp接收緩沖區的默認值 [root@qljt core]# cat /proc/sys/net/core/wmem_default 111616 111616:udp發送緩沖區的默認值 . tcp 或udp收發緩沖區最小值 tcp 或udp接收緩沖區的最小值為 256 bytes,由內核的宏決定; tcp 或udp發送緩沖區的最小值為 2048 bytes,由內核的宏決定 setsockopt設置socket狀態 1.closesocket(一般不會立即關閉而經歷TIME_WAIT的過程)後想繼續重用該socket: BOOL bReuseaddr=TRUE; setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL)); 2. 如果要已經處於連接狀態的soket在調用closesocket後強制關閉,不經歷TIME_WAIT的過程: BOOL bDontLinger = FALSE; setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL)); 3.在send(),recv()過程中有時由於網路狀況等原因,發收不能預期進行,而設置收發時限: int nNetTimeout=1000;//1秒 //發送時限 setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int)); //接收時限 setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int)); 4.在send()的時候,返回的是實際發送出去的位元組(同步)或發送到socket緩沖區的位元組(非同步);系統默認的狀態發送和接收一次為8688位元組(約為8.5K);在實際的過程中發送數據 和接收數據量比較大,可以設置socket緩沖區,而避免了send(),recv()不斷的循環收發: // 接收緩沖區 int nRecvBuf=32*1024;//設置為32K setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int)); //發送緩沖區 int nSendBuf=32*1024;//設置為32K setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int)); 5. 如果在發送數據的時,希望不經歷由系統緩沖區到socket緩沖區的拷貝而影響程序的性能: int nZero=0; setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero)); 6.同上在recv()完成上述功能(默認情況是將socket緩沖區的內容拷貝到系統緩沖區): int nZero=0; setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int)); 7.一般在發送UDP數據報的時候,希望該socket發送的數據具有廣播特性: BOOL bBroadcast=TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL)); 8.在client連接伺服器過程中,如果處於非阻塞模式下的socket在connect()的過程中可以設置connect()延時,直到accpet()被呼叫(本函數設置只有在非阻塞的過程中有顯著的 作用,在阻塞的函數調用中作用不大) BOOL bConditionalAccept=TRUE; setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL)); 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)); 設置套介面的選項。 #include <winsock.h> int PASCAL FAR setsockopt( SOCKET s, int level, int optname, const char FAR* optval, int optlen); s:標識一個套介面的描述字。 level:選項定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。 optname:需設置的選項。 optval:指針,指向存放選項值的緩沖區。 optlen:optval緩沖區的長度。 注釋: setsockopt()函數用於任意類型、任意狀態套介面的設置選項值。盡管在不同協議層上存在選項,但本函數僅定義了最高的「套介面」層次上的選項。選項影響套介面的操作,諸如加急數據是否在普通數據流中接收,廣播數據是否可以從套介面發送等等。 有兩種套介面的選項:一種是布爾型選項,允許或禁止一種特性;另一種是整形或結構選項。允許一個布爾型選項,則將optval指向非零整形數;禁止一個選項optval指向一個等於零的整形數。對於布爾型選項,optlen應等於sizeof(int);對其他選項,optval指向包含所需選項的整形數或結構,而optlen則為整形數或結構的長度。SO_LINGER選項用於控制下述情況的行動:套介面上有排隊的待發送數據,且 closesocket()調用已執行。參見closesocket()函數中關於SO_LINGER選項對closesocket()語義的影響。應用程序通過創建一個linger結構來設置相應的操作特性: struct linger { int l_onoff; int l_linger; }; 為了允許SO_LINGER,應用程序應將l_onoff設為非零,將l_linger設為零或需要的超時值(以秒為單位),然後調用setsockopt()。為了允許SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff應設為零,然後調用setsockopt()。 預設條件下,一個套介面不能與一個已在使用中的本地地址捆綁(參見bind())。但有時會需要「重用」地址。因為每一個連接都由本地地址和遠端地址的組合唯一確定,所以只要遠端地址不同,兩個套介面與一個地址捆綁並無大礙。為了通知WINDOWS套介面實現不要因為一個地址已被一個套介面使用就不讓它與另一個套介面捆綁,應用程序可在bind()調用前先設置SO_REUSEADDR選項。請注意僅在bind()調用時該選項才被解釋;故此無需(但也無害)將一個不會共用地址的套介面設置該選項,或者在bind()對這個或其他套介面無影響情況下設置或清除這一選項。 一個應用程序可以通過打開SO_KEEPALIVE選項,使得WINDOWS套介面實現在TCP連接情況下允許使用「保持活動」包。一個WINDOWS套介面實現並不是必需支持「保持活動」,但是如果支持的話,具體的語義將與實現有關,應遵守RFC1122「Internet主機要求-通訊層」中第 4.2.3.6節的規范。如果有關連接由於「保持活動」而失效,則進行中的任何對該套介面的調用都將以WSAENETRESET錯誤返回,後續的任何調用將以WSAENOTCONN錯誤返回。 TCP_NODELAY選項禁止Nagle演算法。Nagle演算法通過將未確認的數據存入緩沖區直到蓄足一個包一起發送的方法,來減少主機發送的零碎小數據包的數目。但對於某些應用來說,這種演算法將降低系統性能。所以TCP_NODELAY可用來將此演算法關閉。應用程序編寫者只有在確切了解它的效果並確實需要的情況下,才設置TCP_NODELAY選項,因為設置後對網路性能有明顯的負面影響。TCP_NODELAY是唯一使用IPPROTO_TCP層的選項,其他所有選項都使用SOL_SOCKET層。 如果設置了SO_DEBUG選項,WINDOWS套介面供應商被鼓勵(但不是必需)提供輸出相應的調試信息。但產生調試信息的機制以及調試信息的形式已超出本規范的討論范圍。 setsockopt()支持下列選項。其中「類型」表明optval所指數據的類型。 選項 類型 意義 SO_BROADCAST BOOL 允許套介面傳送廣播信息。 SO_DEBUG BOOL 記錄調試信息。 SO_DONTLINER BOOL 不要因為數據未發送就阻塞關閉操作。設置本選項相當於將SO_LINGER的l_onoff元素置為零。 SO_DONTROUTE BOOL 禁止選徑;直接傳送。 SO_KEEPALIVE BOOL 發送「保持活動」包。 SO_LINGER struct linger FAR* 如關閉時有未發送數據,則逗留。 SO_OOBINLINE BOOL 在常規數據流中接收帶外數據。 SO_RCVBUF int 為接收確定緩沖區大小。 SO_REUSEADDR BOOL 允許套介面和一個已在使用中的地址捆綁(參見bind())。 SO_SNDBUF int 指定發送緩沖區大小。 TCP_NODELAY BOOL 禁止發送合並的Nagle演算法。 setsockopt()不支持的BSD選項有: 選項名 類型 意義 SO_ACCEPTCONN BOOL 套介面在監聽。 SO_ERROR int 獲取錯誤狀態並清除。 SO_RCVLOWAT int 接收低級水印。 SO_RCVTIMEO int 接收超時。 SO_SNDLOWAT int 發送低級水印。 SO_SNDTIMEO int 發送超時。 SO_TYPE int 套介面類型。 IP_OPTIONS 在IP頭中設置選項。 返回值: 若無錯誤發生,setsockopt()返回0。否則的話,返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。 錯誤代碼: WSANOTINITIALISED:在使用此API之前應首先成功地調用WSAStartup()。 WSAENETDOWN:WINDOWS套介面實現檢測到網路子系統失效。 WSAEFAULT:optval不是進程地址空間中的一個有效部分。 WSAEINPROGRESS:一個阻塞的WINDOWS套介面調用正在運行中。 WSAEINVAL:level值非法,或optval中的信息非法。 WSAENETRESET:當SO_KEEPALIVE設置後連接超時。 WSAENOPROTOOPT:未知或不支持選項。其中,SOCK_STREAM類型的套介面不支持SO_BROADCAST選項,SOCK_DGRAM 類型的套介面不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE選項。 WSAENOTCONN:當設置SO_KEEPALIVE後連接被復位。 WSAENOTSOCK:描述字不是一個套介面。

㈡ linux下怎麼獲取tcp發送緩沖區還有多少空閑

int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);

參數
sockfd:一個標識套介面的描述字。
level:選項定義的層次。支持的層次僅有SOL_SOCKET和IPPROTO_TCP。
optname:需獲取的套介面選項。
optval:指針,指向存放所獲得選項值的緩沖區。
optlen:指針,指向optval緩沖區的長度值。

返回值:
若無錯誤發生,getsockopt()返回0。否則的話,返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
錯誤代碼:
WSANOTINITIALISED:在使用此API之前應首先成功地調用WSAStartup()。
WSAENETDOWN:WINDOWS套介面實現檢測到網路子系統失效。
WSAEFAULT:optlen參數非法。
WSAEINPROGRESS:一個阻塞的WINDOWS套介面調用正在運行中。
WSAENOPROTOOPT:未知或不支持選項。其中,SOCK_STREAM類型的套介面不支持SO_BROADCAST選項,SOCK_DGRAM類型的套介面不支持SO_ACCEPTCONN、SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE選項。
WSAENOTSOCK:描述字不是一個套介面。

注釋:
編輯
getsockopt()函數用於獲取任意類型、任意狀態套介面的選項當前值,並把結果存入optval。在不同協議層上存在選項,但往往是在最高的「套介面」層次上,設置選項影響套介面的操作,諸如操作的阻塞與否、包的選徑方式、帶外數據的傳送等。
被選中選項的值放在optval緩沖區中。optlen所指向的整形數在初始時包含緩沖區的長度,在調用返回時被置為實際值的長度。對SO_LINGER選項而言,相當於linger結構的大小,對其他選項來說,是一個整形數的大小。
如果未進行setsockopt()調用,則getsockopt()返回系統預設值。
getsockopt()支持下列選項。其中「類型」欄指出了optval所指向的值。僅有TCP_NODELAY選項使用了IPPROTO_TCP層;其餘選項均使用SOL_SOCKET層。
選項 類型 意義
SO_ACCEPTCONN BOOL 套介面正在用listen()監聽。
SO_BROADCAST BOOL 套介面設置為傳送廣播信息。
SO_DEBUG BOOL 允許調試。
SO_DONTLINER BOOL 若為真,則SO_LINGER選項被禁止。
SO_DONTROUTE BOOL 禁止選徑。
SO_ERROR int 獲取錯誤狀態並清除。
SO_KEEPALIVE BOOL 發送「保持活動」信息。
SO_LINGER struct linger FAR* 返回當前各linger選項。
SO_OOBINLINE BOOL 在普通數據流中接收帶外數據。
SO_RCVBUF int 接收緩沖區大小。
SO_REUSEADDR BOOL 套介面能和一個已在使用中的地址捆綁。
SO_SNDBUF int 發送緩沖區大小。
SO_TYPE int 套介面類型(如SOCK_STREAM)。
TCP_NODELAY BOOL 禁止發送合並的Nagle演算法。
getsockopt()不支持的BSD選項有:
選項名 類型 意義
SO_RCVLOWAT int 接收低級水印。
SO_RCVTIMEO int 接收超時。
SO_SNDLOWAT int 發送低級水印。
SO_SNDTIMEO int 發送超時。
IP_OPTIONS 獲取IP頭中選項。
TCP_MAXSEG int 獲取TCP最大段的長度。
用一個未被支持的選項去調用getsockopt()將會返回一個WSAENOPROTOOPT錯誤代碼(可用WSAGetLastError()獲取)。

㈢ Linux下C語言Socket編程問題(高手進)

網路斷開如拔掉網線時,系統程序一般是檢測不出來的,尤其是廣域網上。

建議連接時設置linger屬性,如果網路不通,能迅速決斷立即返回失敗錯誤。
LINGER oLinger;
oLinger.l_onoff = 1;
oLinger.l_linger = 0;
setsockopt(m_Socket,SOL_SOCKET,SO_LINGER,(char *)&oLinger,sizeof(oLinger));

㈣ linux apache 性能調優 8G 8核 的伺服器

[檢測工具]

為了得到完整的調試結果,建議你採用 ApacheBench 或者 httperf之類的軟體。如果你對非 LAMP 架構的伺服器測試有興趣的話,建議你採用微軟的免費軟體: Web Application Stress Tool(需要 NT 或者 2000)。 (其它伺服器測試工具)

檢測 Apache ,採用 top d 1 顯示所有進程的 CPU 和內存情況。另外,還採用 apachectl status 命令

[硬體優化]

1、升級硬體的一般規則:對於 php 腳本而言,主要的瓶頸是 CPU ,對於靜態頁面而言,瓶頸是內存和網路。一台 400 Mhz 的普通奔騰機器所下載的靜態頁面就能讓 T3 專線(45Mbps)飽和。

2、採用 hdparm 來優化磁碟,一般能提升 IDE 磁碟讀寫性能 200%,但是對 SCSI 硬碟也有效果。(不同類型的硬碟對比)

[策略優化]

3、Apache 處理 PHP 腳本的速度要比靜態頁面慢 2-10 倍,因此盡量採用多的靜態頁面,少的腳本。

4、PHP 腳本如果不做緩沖,每次調用都需要編譯,因此,安裝一個 PHP 緩沖產品能提升 25-100% 的性能。

5、如果你採用了 Linux 系統,建議升級內核到 2.4,因為靜態頁面由內核服務。

6、另外一項緩沖技術是把不常修改的 PHP 頁面採用 HTML 緩沖輸出。

7、不要在 Web 伺服器上運行 X-Windows ,關掉沒有必要運行的進程。

8、如果能夠用文本就不要用圖像,盡量減小圖片的尺寸。

9、分散負載,把資料庫伺服器放到另外的機器上去。採用另外低端的機器服務圖片和 HTML 頁面,如果所有的靜態頁面在另外一台伺服器上處理,可以設置 httpd.conf 中的 KeepAlives 為 off ,來減少斷開連接的時間。

10、以上所有的方法都是針對單機而言的,如果你覺得系統還是不夠快,可以採用集群,負載均衡,緩沖技術。採用 Squid 作為緩沖,配置 Squid 的方法。

[編譯優化]

11、把基於文件的會話切換到基於共享內存的會話。編譯 PHP 時採用 --with-mm 選項,在 php.ini 中設置 set session.save_handler=mm 。這個簡單的修改能讓會話管理時間縮短一半。

12、採用最新版本的 Apache ,並把 PHP 編譯其中,或者採用 DSO 模式,不要採用 CGI 方式。

13、編譯 PHP 時,建議採用如下的參數:
--enable-inline-optimization --disable-debug

[配置優化]

14、修改 httpd.conf :
# 關閉 DNS lookups,PHP 腳本只拿 IP 地址
HostnameLookups off

15、如果網路擁擠,CPU 資源不夠用,採用 PHP 的 HTML 壓縮功能:
output_handler = ob_gzhandler
PHP 4.0.4 的用戶請不要使用,因為存在內存泄漏問題。

16、修改 httpd.conf 中的 SendBufferSize 為你最大的頁面文件的大小。加大內核的 TCP/IP 寫緩沖大小。

17、採用資料庫的持久連接時,不要把 MaxRequestsPerChild 設置得太大。

[第三方軟體優化]

18、如果喜歡從修改 Apache 源碼入手,可以安裝 lingerd。在頁面產生和發送後,每個 Apache 進程都會浪費一段時光在客戶連接上,Lingerd 能接管這項工作,讓 Apache 迅速服務下一個客戶請求。

19、如果你足夠勇敢的話,還可以採用 Silicon Graphics 的 Accelerated Apache 補丁。這個工程能使 Apache 1.3 快 10 倍,使 Apache 2.0 快 4 倍。

安裝一個 PHP 緩沖產品能提升 25-100% 的性能。

[Linux系統優化]

1.清理伺服器磁碟碎片:

不論Linux文件系統採用什麼文件格式(ext3、JFS、XFS、ReiserFS )、何種類型的硬碟(IDE 、SCSI),隨著時間的推移文件系統都會趨向於碎片化。ext3、JFS等高級文件系統可以減少文件系統的碎片化,但是並沒有消除。在繁忙的資料庫伺服器中,隨著時間的過去,文件碎片化將降低硬碟性能,硬碟性能從硬碟讀出或寫入數據時才能注意到。時間長了會發現每個磁碟上確實積累了非常多的垃圾文件,釋放磁碟空間可以幫助系統更好地工作。Linux最好的整理磁碟碎片的方法是做一個完全的備份,重新格式化分區,然後從備份恢復文件。但是對於7×24小時工作關鍵任務伺服器來說是比較困難的。Kleandisk是一個高效的磁碟清理工具,它能把磁碟上的文件分成不同的"組",比如把所有的"core"文件歸成一組(Group),這樣要刪除所有core文件時只要刪除這個組就行了。core文件是當軟體運行出錯時產生的文件,它對於軟體開發人員比較有用,對於其他用戶(比如電子郵件伺服器)卻沒有任何意義。因此,如果沒有軟體開發的需要,見到core文件就可以將其刪除。

2、開啟硬碟DMA

現在使用的IDE硬碟基本支持DMA66/100/133(直接內存讀取)但是Linux發行版本安裝後一般沒有打開,可以 /etc/rc.d/rc.local 最後面加上一行: /sbin/hdparm -d1 –x66 -c3 -m16 /dev/hda 這樣以後每次開機,硬碟的 DMA 就會開啟,不必每次手動設定。添加前後你可以使用命令:hdparm -Tt /dev/hda 來測試對比一下。

3、調整緩沖區刷新參數

Linux內核中,包含了一些對於系統運行態的可設置參數。緩沖刷新的參數可以通過調整 /proc/sys/vm/bdflush文件來完成,這個文件的格式是這樣的:

「mode」的值表示工作模式,共有0、1、2和3四種模式,這里設定為0。Bonding工作在負載均衡(Load Balancing (round-robin))方式下,即兩塊網卡同時工作,這時理論上Bonding能提供兩倍的帶寬。Bonding運行在網卡的混雜(Promisc)模式下,而且它將兩塊網卡的MAC地址修改為一樣的。混雜模式就是網卡不再只接收目的硬體地址是自身MAC地址的數據幀,而是可以接收網路上所有的幀。

5、減少虛擬終端機的數量。

Linux安裝後系統默認是6個虛擬終端機,也就是 CTRL+ALT F1~F6 那六個,作為伺服器使用可以關掉其中四個,只留下 CTRL+ALT F1~F2,大約省下 4 Mbytes 的內存,但是這樣一來,X-Window 會從原來的 CTRL+ALT F7 變成 CTRL+ALT F3 。 修改 /etc/inittab 中,將 mingetty 3 ~6 全部加上 # 字型大小 。

6. 關閉一些不用的服務

Linux伺服器在啟動時需要啟動很多系統服務,它們向本地和網路用戶提供了Linux的系統功能介面,直接面向應用程序和用戶。提供這些服務的程序是由運行在後台的守護進程(daemons)來執行的。守護進程是生存期長的一種進程。它們獨立於控制終端並且周期性的執行某種任務或等待處理某些發生的事件。他們常常在系統引導裝入時啟動,在系統關閉時終止。linux系統有很多守護進程,大多數伺服器都是用守護進程實現的。如Web服務http等。同時,守護進程完成許多系統任務,比如,作業規劃進程crond、列印進程lqd等。

㈤ linux伺服器圖文界面登陸不上

圖形已經開啟,並未關閉的情況下再次執行startx 會有這個提示。

Ctrl+Alt+F7 切過去看是否能夠進入圖形界面。

然後查看下 cat /etc/inittab |grep id

如果出來的信息里有3 那麼你重啟下,再次執行startx 應該可以直接進入圖形界面下

如果出來的信息里有5 那麼你重啟後,會直接進入圖形界面,不需要再執行startx

㈥ close wait是什麼

close wait的意思到底是什麼?下面是我給大家整理的close wait是什麼,供大家參閱!

close wait是什麼

等待結束

淺談CLOSE WAIT

TCP 有很多連接狀態,每一個都夠聊十塊錢兒的,比如我們以前討論過TIME_WAIT 和FIN_WAIT1,最近時不時聽人提起 CLOSE_WAIT,感覺有必要梳理一下。

所謂 CLOSE_WAIT,借用某位大牛的話來說應該倒過來叫做 WAIT_CLOSE,也就是說「等待關閉」,如果你還不理解其含義,可以看看 TCP 關閉連接時的圖例:

TCP Close

不要被圖中的 client 和 server 所迷惑,你只要記住:主動關閉的一方發出 FIN 包,被動關閉的一方響應 ACK 包,此時,被動關閉的一方就進入了 CLOSE_WAIT 狀態。如果一切正常,稍後被動關閉的一方也會發出 FIN 包,然後遷移到 LAST_ACK 狀態。

通常,CLOSE_WAIT 狀態在伺服器停留時間很短,如果你發現大量的 CLOSE_WAIT 狀態,那麼就意味著被動關閉的一方沒有及時發出 FIN 包,一般有如下幾種可能:

程序問題:代碼層面遺漏或者死循環之類的,沒有 close 相應的 socket 連接。

響應太慢:對方已經 timeout 了,本方還忙於耗時邏輯,導致 close 被延後。

BACKLOG 太大:隊列堆積嚴重,導致多餘的請求來不及消費就被關閉了。

如果遭遇了 CLOSE_WAIT 故障,那麼需要立刻通過「netstat」或者「ss」命令來判斷 CLOSE_WAIT 連接是哪些進程引起的,如果是我們自己寫的一些程序,比如用 HttpClient 自定義的蜘蛛,那麼八九不離十是忘記了 close 相應的 socket,如果是一些使用廣泛的程序,比如 Tomcat 之類的,那麼不太可能是它們自身的 BUG,更可能是響應速度太慢或者 BACKLOG 設置過大導致的故障。

此外還有一點需要說明:按照前面圖例所示,當被動關閉的一方處於 CLOSE_WAIT 狀態時,主動關閉的一方處於 FIN_WAIT2 狀態。 那麼為什麼我們總聽說 CLOSE_WAIT 狀態過多的故障,但是卻相對少聽說 FIN_WAIT2 狀態過多的故障呢?這是因為 Linux 有一個「tcp_fin_timeout」設置,控制了 FIN_WAIT2 的最大生命周期。壞消息是 CLOSE_WAIT 沒有類似的設置,如果不重啟進程,那麼 CLOSE_WAIT 狀態很可能會永遠持續下去;好消息是如果連接開啟了 keepalive機制,那麼可以通過對應的設置來清理無效連接,不過 keepalive 是治標不治本的方法,還是應該對照前面的解釋找到問題的症結才對。

本來想多寫點的,但是著急下班回家,就寫到這吧,結尾推薦兩個案例:

PHP升級導致系統負載過高問題分析

又見CLOSE_WAIT

CLOSE WAIT狀態的生成原因

首先我們知道,如果我們的Client程序處於CLOSE_WAIT狀態的話,說明套接字是被動關閉的!

因為如果是Server端主動斷掉當前連接的話,那麼雙方關閉這個TCP連接共需要四個packet:

Server ---> FIN ---> Client

Server <--- ACK <--- Client

這時候Server端處於FIN_WAIT_2狀態;而我們的程序處於CLOSE_WAIT狀態。

Server <--- FIN <--- Client

這時Client發送FIN給Server,Client就置為LAST_ACK狀態。

Server ---> ACK ---> Client

Server回應了ACK,那麼Client的套接字才會真正置為CLOSED狀態。

我們的程序處於CLOSE_WAIT狀態,而不是LAST_ACK狀態,說明還沒有發FIN給Server,那麼可能是在關閉連接之前還有許多數據要發送或者其他事要做,導致沒有發這個FIN packet。

原因知道了,那麼為什麼不發FIN包呢,難道會在關閉己方連接前有那麼多事情要做嗎?

elssann舉例說,當對方調用closesocket的時候,我的程序正在調用recv中,這時候有可能對方發送的FIN包我沒有收到,而是由TCP代回了一個ACK包,所以我這邊套接字進入CLOSE_WAIT狀態。

所以他建議在這里判斷recv函數的返回值是否已出錯,是的話就主動closesocket,這樣防止沒有接收到FIN包。

因為前面我們已經設置了recv超時時間為30秒,那麼如果真的是超時了,這里收到的錯誤應該是WSAETIMEDOUT,這種情況下也可以主動關閉連接的。

還有一個問題,為什麼有數千個連接都處於這個狀態呢?難道那段時間內,伺服器端總是主動拆除我們的連接嗎?

不管怎麼樣,我們必須防止類似情況再度發生!

首先,我們要保證原來的埠可以被重用,這可以通過設置SO_REUSEADDR套接字選項做到:

重用本地地址和埠

以前我總是一個埠不行,就換一個新的使用,所以導致讓數千個埠進入CLOSE_WAIT狀態。如果下次還發生這種尷尬狀況,我希望加一個限定,只是當前這個埠處於CLOSE_WAIT狀態!

在調用

sockConnected = socket(AF_INET, SOCK_STREAM, 0);

之後,我們要設置該套接字的選項來重用:

/// 允許重用本地地址和埠:

/// 這樣的好處是,即使socket斷了,調用前面的socket函數也不會佔用另一個,而是始終就是一個埠

/// 這樣防止socket始終連接不上,那麼按照原來的做法,會不斷地換埠。

int nREUSEADDR = 1;

setsockopt(sockConnected,

SOL_SOCKET,

SO_REUSEADDR,

(const char*)&nREUSEADDR,

sizeof(int));

教科書上是這么說的:這樣,假如伺服器關閉或者退出,造成本地地址和埠都處於TIME_WAIT狀態,那麼SO_REUSEADDR就顯得非常有用。

也許我們無法避免被凍結在CLOSE_WAIT狀態永遠不出現,但起碼可以保證不會佔用新的埠。

其次,我們要設置SO_LINGER套接字選項:

從容關閉還是強行關閉?

LINGER是“拖延”的意思。

默認情況下(Win2k),SO_DONTLINGER套接字選項的是1;SO_LINGER選項是,linger為{l_onoff:0,l_linger:0}。

如果在發送數據的過程中(send()沒有完成,還有數據沒發送)而調用了closesocket(),以前我們一般採取的措施是“從容關閉”:

因為在退出服務或者每次重新建立socket之前,我都會先調用

/// 先將雙向的通訊關閉

shutdown(sockConnected, SD_BOTH);

/// 安全起見,每次建立Socket連接前,先把這個舊連接關閉

closesocket(sockConnected);

我們這次要這么做:

設置SO_LINGER為零(亦即linger結構中的l_onoff域設為非零,但l_linger為0),便不用擔心closesocket調用進入“鎖定”狀態(等待完成),不論是否有排隊數據未發送或未被確認。這種關閉方式稱為“強行關閉”,因為套接字的虛電路立即被復位,尚未發出的所有數據都會丟失。在遠端的recv()調用都會失敗,並返回WSAECONNRESET錯誤。

在connect成功建立連接之後設置該選項:

linger m_sLinger;

m_sLinger.l_onoff = 1; // (在closesocket()調用,但是還有數據沒發送完畢的時候容許逗留)

m_sLinger.l_linger = 0; // (容許逗留的時間為0秒)

setsockopt(sockConnected,

SOL_SOCKET,

SO_LINGER,

(const char*)&m_sLinger,

sizeof(linger));

總結

也許我們避免不了CLOSE_WAIT狀態凍結的再次出現,但我們會使影響降到最小,希望那個重用套接字選項能夠使得下一次重新建立連接時可以把CLOSE_WAIT狀態踢掉。

我的意思是:當一方關閉連接後,另外一方沒有檢測到,就導致了CLOSE_WAIT的出現,上次我的一個朋友也是這樣,他寫了一個客戶端和 APACHE連接,當APACHE把連接斷掉後,他沒檢測到,出現了CLOSE_WAIT,後來我叫他檢測了這個地方,他添加了調用 closesocket的代碼後,這個問題就消除了。

如果你在關閉連接前還是出現CLOSE_WAIT,建議你取消shutdown的調用,直接兩邊closesocket試試。

另外一個問題:

比如這樣的一個例子:

當客戶端登錄上伺服器後,發送身份驗證的請求,伺服器收到了數據,對客戶端身份進行驗證,發現密碼錯誤,這時候伺服器的一般做法應該是先發送一個密碼錯誤的信息給客戶端,然後把連接斷掉。

如果把

m_sLinger.l_onoff = 1;

m_sLinger.l_linger = 0;

這樣設置後,很多情況下,客戶端根本就收不到密碼錯誤的消息,連接就被斷了。

出現CLOSE_WAIT的原因很簡單,就是某一方在網路連接斷開後,沒有檢測到這個錯誤,沒有執行closesocket,導致了這個狀態的實現,這在TCP/IP協議的狀態變遷圖上可以清楚看到。同時和這個相對應的還有一種叫TIME_WAIT的。

另外,把SOCKET的SO_LINGER設置為0秒拖延(也就是立即關閉)在很多時候是有害處的。

還有,把埠設置為可復用是一種不安全的網路編程方法。

能不能解釋請看這里

http://blog.csdn.net/cqq/archive/2005/01/26/269160.aspx

再看這個圖:

斷開連接的時候,

當發起主動關閉的左邊這方發送一個FIN過去後,右邊被動關閉的這方要回應一個ACK,這個ACK是TCP回應的,而不是應用程序發送的,此時,被動關閉的一方就處於CLOSE_WAIT狀態了。如果此時被動關閉的這一方不再繼續調用closesocket,那麼他就不會發送接下來的FIN,導致自己老是處於CLOSE_WAIT。只有被動關閉的這一方調用了closesocket,才會發送一個FIN給主動關閉的這一方,同時也使得自己的狀態變遷為LAST_ACK。

比如被動關閉的是客戶端。。。

當對方調用closesocket的時候,你的程序正在

int nRet = recv(s,....);

if (nRet == SOCKET_ERROR)

{// closesocket(s);return FALSE;}

很多人就是忘記了那句closesocket,這種代碼太常見了。

我的理解,當主動關閉的一方發送FIN到被動關閉這邊後,被動關閉這邊的TCP馬上回應一個ACK過去,同時向上面應用程序提交一個ERROR,導致上面的SOCKET的send或者recv返回SOCKET_ERROR,正常情況下,如果上面在返回SOCKET_ERROR後調用了 closesocket,那麼被動關閉的者一方的TCP就會發送一個FIN過去,自己的狀態就變遷到LAST_ACK.

㈦ 一文帶你搞定TCP揮手

TCP斷開連接,需要經歷四次揮手,通信的雙方都可主動斷開連接,斷開連接通信的雙方佔用的資源將會被釋放。

為什麼回收需要四次

原因是客戶端在主動發起FIN報文以後僅表示客戶端不再主動發送數據了但是還可以接收數據。伺服器在響應ACK報文以後,還有可能有數據還在處理且需要發送給客戶端,因此當伺服器處理完這些數據以後才能發送FIN報文表示同意關閉連接。

因此服務端的ACK和FIN報文需要分開發送,揮手也就變成了4次。

什麼是MSL和TTL

TTL是IP頭部中的一個欄位,是指IP數據報可以經過的最大路由數,每經過一個路由器都需要減1,當TTL值為0時數據報就會被丟棄,同時發送ICMP報文給源主機。TTL的單位是路由跳數。

MSL是報文在網路中存在的最長時間,超過該時間就會被丟棄。

為什麼TIME_WAIT需要經歷2MSL後才可以變為CLOSED

網路中存在的發送方數據包,首先需要發送給服務端,服務端在處理完以後又會將相應發送給客戶端,所以總共需要2個倍的時間。

2MSL的時間是從客戶端接收到FIN報文並且發送ACK報文時開始的。如果此時ACK報文沒有被服務端接收到觸發了服務端的超時重傳,客戶端又再次收到了FIN報文,那麼2MSL將重新開始計時。

LINUX中默認一個MSL是30s,也就是說TIME_WAIT的時間是60s。

為什麼需要TIME_WAIT狀態

主動發起連接中斷的一方需要有TIME_WAIT狀態,主要是以下原因:

防止舊連接的數據包被收到

假設沒有TIME_WAIT狀態,如果有相同的埠的TCP連接被服用後,上圖中被延遲SEQ=301的數據包抵達了客戶端,客戶端是有可能正常接收該報文的,此時就會產生數據錯亂現象。

但通過2MSL的等待時間,通信雙方的數據包都可以在網路中消失,新的數據包一定是新連接的。

保證連接正確關閉

通過等待2MSL的時間確保最後一次ACK報文被被動斷開連接的一方收到,從而正常關閉。

上圖如果服務端沒有收到最後一個ACK報文會處於LAST_ACK狀態,如果此時客戶端發起了一個新的SYN報文請求建立連接,服務端會發送RST報文給客戶端,連接建立失敗。

但是通過等待2MSL的時間會解決上述問題,因為假設服務端沒有收到最後一次ACK報文,會觸發超時重傳重新發送FIN報文並等待新的ACK報文。客戶端在收到新的FIN報文時會重新發送ACK報文並刷新2MSL的計時,最終能夠保證服務端的連接能夠正常關閉。

TIME_WAIT過多的弊端

伺服器如果有TIME_WAIT狀態的連接,說明TCP連接的斷開是由服務端發起的,此時如果TIME_WAIT的連接過多,將會出現以下問題:

TIME_WAIT的優化主要有以下幾種方式,每種方式都有利有弊:

打開net.ipv4.tcp_tw_reuse和net.ipv4.tcp_timestamps選項

參數開啟以後,可以復用處於TIME_WAIT的Socket給新的連接使用。

tcp_tw_reuse的功能只能用於連接發起方,開啟該參數以後,在調用connect函數時,內核會隨機找一個time_wait超過1s的連接給新的連接復用。

net.ipv4.tcp_timestamp默認開啟,表示打開對TCP時間戳的支持。時間戳欄位存儲在TCP頭部的選項欄位中,用於記錄TCP發送方的時間戳和從對端接收到的最新時間戳。

net.ipv4.tcp_max_tw_buckets

當系統中的TIME_WAIT的連接數超過該項的值時,系統那個會將後面TIME_WAIT的連接重置,不推薦使用。

程序使用SO_LINGER

通過設置Sokcet的一些選項,來影響close方法的一些行為。

如果SO_LINGER中的onoff為非0,並且linger為0,調用close方法以後會立即發送一個RST報文給對方,TCP連接會直接跳過四次握手關閉。也過於暴力不推薦。

在某個時間段內,如果TCP連接上無任何活動,TCP保活機制開始生效,每隔一段時間就會發送一個探測報文,如果連續幾個探測報文都沒有收到響應,則認為TCP連接已死,系統內核會將錯誤信息通知給應用程序。

上述三個都是Linux中的默認值,也就是說Linux操作系統中至少經過2小時11分15秒才可以發現一個死亡連接。

Java中的ServerSokcet的初始化方法中有一個backlog參數,該參數在Linux2.2以前代表SYN隊列大小,但是在Linux 2.2以後就是全連接隊列的大小(accept隊列的大小)。

Socket的一些連接操作對應的tcp連接步驟

close方法對應的TCP四次揮手

㈧ 幫忙詳細解釋下linux 的netstat -s 結果顯示,越詳細越好,謝謝!

tcp/ip的基礎知識;不懂的話,我給你翻譯出來也是白搭;
大意就是:tcp中請求同步,以及應答等過程;
L1:(數字是序列號)請求同步發送;
L2:收到的同步請求;
L3:無效的請求同步;
L4:重置原始的socket的SYN_RECV狀態;
L5:1171個包從接收隊列中移除,因為套接字緩沖區溢出了;
L6: 240357 ICMP數據包丟棄,因為它們超出了窗口
L7:8538個網際網路控制報文數據包丟棄了;由於socket被鎖定了;
L8:地址解析協議過濾器:0

㈨ linux下要想reuse port怎麼辦

基本套介面選項
SO_BROADCAST: default = off
SO_DEBUG: default = off
SO_DONTROUTE: default = off
SO_ERROR: default = 0
SO_KEEPALIVE: default = off
SO_LINGER: default = l_onoff = 0, l_linger = 0
SO_OOBINLINE: default = off
SO_RCVBUF: default = 87380
SO_SNDBUF: default = 16384
SO_RCVLOWAT: default = 1
SO_SNDLOWAT: default = 1
SO_RCVTIMEO: default = 0 sec, 0 usec
SO_SNDTIMEO: default = 0 sec, 0 usec
SO_REUSEADDR: default = off
SO_REUSEPORT: (undefined)
SO_TYPE: default = 1
SO_USELOOPBACK: (undefined)

//IPv4選項
IP_HDRINCL: default = off
IP_RECVDSTADDR: (undefined)
IP_RECVIF: (undefined)
IP_TOS: default = 0
IP_TTL: default = 64
//TCP選項
TCP_KEEPALIVE: (undefined)
TCP_MAXRT: (undefined)
TCP_MAXSEG: default = 536
TCP_NODELAY: default = off

註:undefined就是不支持。

閱讀全文

與linuxlinger相關的資料

熱點內容
lk4102加密晶元 瀏覽:588
怎麼更改app店面 瀏覽:489
設備部門如何做好伺服器 瀏覽:849
androido下載 瀏覽:478
神奇高量戰法副圖源碼 瀏覽:830
匯編語言設計凱撒密碼加密器 瀏覽:392
主次梁加密是加在哪裡 瀏覽:664
模板匹配演算法matlab 瀏覽:825
外地程序員去北京 瀏覽:24
安卓機換蘋果12如何轉移數據 瀏覽:420
互聯網ntp伺服器地址及埠 瀏覽:613
pdf到word轉換器 瀏覽:269
飛行解壓素材 瀏覽:498
51單片機指令用背嗎 瀏覽:936
unityai演算法 瀏覽:834
我的世界ice伺服器如何打開pvp 瀏覽:975
c語言編程如何做標記 瀏覽:884
python數據分析實戰pdf 瀏覽:985
u盤插入文件夾 瀏覽:918
華為amd雲伺服器 瀏覽:497