setsockopt 設置TCP的選項SO_LINGER


SO_LINGER選項用來設置延遲關閉的時間,等待套接字發送緩沖區中的數據發送完成。

沒有設置該選項時,在調用close()后,在發送完FIN后會立即進行一些清理工作並返回。如果設置了SO_LINGER選項,並且等待時間為正值,則在清理之前會等待一段時間。

以調用close()主動關閉為例,在發送完FIN包后,會進入FIN_WAIT_1狀態。如果沒有延遲關閉(即設置SO_LINGER選項),在調用tcp_send_fin()發送FIN后會立即調用sock_orphan()將sock結構從進程上下文中分離。分離后,用戶層進程不會再接收到套接字的讀寫事件,也不知道套接字發送緩沖區中的數據是否被對端接收。如果設置了SO_LINGER選項,並且等待時間為大於0的值,會等待套接字的狀態從FIN_WAIT_1遷移到FIN_WAIT_2狀態。我們知道套接字進入FIN_WAIT_2狀態是在發送的FIN包被確認后,而FIN包肯定是在發送緩沖區中的最后一個字節,所以FIN包的確認就表明發送緩沖區中的數據已經全部被接收。當然,如果等待超過SO_LINGER選項設置的時間后,還是沒有收到FIN的確認,則繼續進行正常的清理工作,Linux下也沒有返回錯誤。從這里看來,SO_LINGER選項的作用是等待發送緩沖區中的數據發送完成,但是並不保證發送緩沖區中的數據一定被對端接收(對端宕機或線路問題),只是說會等待一段時間讓這個過程完成。如果在等待的這段時間里接收到了帶數據的包,還是會給對端發送RST包,並且會reset掉套接字,因為此時已經關閉了接收通道。
在使用這個選項來延遲關閉連接的時候有兩個地方需要注意:
1. 進程會睡眠,直到狀態不為FIN_WAIT_1、CLOSING、LAST_ACK(也就是接收到對FIN的ACK包),或者等待超時
2. 在等待的過程中如果接收到帶數據的包還是會發送RST包
3.消耗更多的額外資源
  TCP協議是一個通用的傳輸層協議,不關心上層具體的業務,如果要延遲關閉連接,最好是結合自己的業務和場景自己來管理,不要依賴這個選項。nginx的延遲關閉就是自己來管理的,覺得要比直接使用SO_LINGER選項好一些,並且不會導致進程阻塞。 ngxin在發送錯誤信息后,會等待一段時間,讓用戶把所有的數據都發送完。超過等待時間后,會直接關閉連接。通過lingering_close,nginx可以保持更好的客戶端兼容性,避免客戶端被reset掉。
  SO_LINGER還有一個作用就是用來減少TIME_WAIT套接字的數量。在設置SO_LINGER選項時,指定等待時間為0,此時調用主動關閉時不會發送FIN來結束連接,而是直接將連接設置為CLOSE狀態,清除套接字中的發送和接收緩沖區,直接對對端發送RST包。

 

 

setsockopt 設置 SO_LINGER 選項

此選項指定函數close對面向連接的協議如何操作(如TCP)。內核缺省close操作是立即返回,如果有數據殘留在套接口緩沖區中則系統將試着將這些數據發送給對方。 

SO_LINGER選項用來改變此缺省設置。使用如下結構:

struct linger {

     int l_onoff; /* 0 = off, nozero = on */

     int l_linger; /* linger time */

};

有下列三種情況:

1、設置 l_onoff為0,則該選項關閉,l_linger的值被忽略,等於內核缺省情況,close調用會立即返回給調用者,如果可能將會傳輸任何未發送的數據;

2、設置 l_onoff為非0,l_linger為0,則套接口關閉時TCP夭折連接,TCP將丟棄保留在套接口發送緩沖區中的任何數據並發送一個RST給對方,而不是通常的四分組終止序列,這避免了TIME_WAIT狀態;

3、設置 l_onoff 為非0,l_linger為非0,當套接口關閉時內核將拖延一段時間(由l_linger決定)。如果套接口緩沖區中仍殘留數據,進程將處於睡眠狀態,直 到(a)所有數據發送完且被對方確認,之后進行正常的終止序列(描述字訪問計數為0)或(b)延遲時間到。此種情況下,應用程序檢查close的返回值是非常重要的,如果在數據發送完並被確認前時間到,close將返回EWOULDBLOCK錯誤且套接口發送緩沖區中的任何數據都丟失。close的成功返回僅告訴我們發送的數據(和FIN)已由對方TCP確認,它並不能告訴我們對方應用進程是否已讀了數據。如果套接口設為非阻塞的,它將不等待close完成。

 注釋:l_linger的單位依賴於實現: 4.4BSD假設其單位是時鍾滴答(百分之一秒),但Posix.1g規定單位為秒。

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

#define TRUE     1

#define FALSE    0
int z;       //Status code

int s;       //Socket s
struct linger so_linger;
...
so_linger.l_onoff = TRUE;
so_linger.l_linger = 30;
z = setsockopt(s,
    SOL_SOCKET,
    SO_LINGER,
    &so_linger,
    sizeof so_linger);
if ( z )
   perror("setsockopt(2)");

 

下面的例子顯示了如何設置SO_LINGER的值來中止套接口s上的當前連接:

#define TRUE     1
#define FALSE    0
int z; /* Status code */
int s;       /* Socket s */
struct linger so_linger;
...
so_linger.l_onoff = TRUE;
so_linger.l_linger = 0;
z = setsockopt(s,
    SOL_SOCKET,
    SO_LINGER,
    &so_linger,
    sizeof so_linger);
if ( z )
    perror("setsockopt(2)");
    close(s); /* Abort connection */

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

 

/********** WINDOWS **********/

/* 當連接中斷時,需要延遲關閉(linger)以保證所有數據都被傳輸,所以需要打開SO_LINGER這個選項;  
 * //注:大致意思就是說SO_LINGER選項用來設置當調用closesocket時是否馬上關閉socket; 
 * linger的結構在/usr/include/Linux/socket.h中定義://注:這個結構就是SetSocketOpt中的Data的數據結構 
 *  struct linger 
 *  { 
 *   int l_onoff;  /* Linger active */       //低字節,0和非0,用來表示是否延時關閉socket
 *   int l_linger; /* How long to linger */   //高字節,延時的時間數,單位為秒
 *  }; 
 *  如果l_onoff為0,則延遲關閉特性就被取消。

 *   如果非零,則允許套接口延遲關閉; l_linger字段則指明延遲關閉的時間 
 */


更具體的描述如下:
1、若設置了SO_LINGER(亦即linger結構中的l_onoff域設為非零),並設置了零超時間隔,則closesocket()不被阻塞立即執行,不論是否有排隊數據未發送或未被確認。這種關閉方式稱為“強制”或“失效”關閉,因為套接口的虛電路立即被復位,且丟失了未發送的數據。在遠端的recv()調用將以WSAECONNRESET出錯。

2、若設置了SO_LINGER並確定了非零的超時間隔,則closesocket()調用阻塞進程,直到所剩數據發送完畢或超時。這種關閉稱為“優雅”或“從容”關閉。請注意如果套接口置為非阻塞且SO_LINGER設為非零超時,則closesocket()調用將以WSAEWOULDBLOCK錯誤返回。

3、若在一個流類套接口上設置了SO_DONTLINGER(也就是說將linger結構的l_onoff域設為零),則closesocket()調用立即返回。但是,如果可能,排隊的數據將在套接口關閉前發送。請注意,在這種情況下WINDOWS套接口實現將在一段不確定的時間內保留套接口以及其他資源,這對於想用所以套接口的應用程序來說有一定影響。
 

SO_DONTLINGER 若為真,則SO_LINGER選項被禁止。
SO_LINGER延遲關閉連接 struct linger上面這兩個選項影響close行為;


 選項                            間隔    關閉方式  等待關閉與否
  SO_DONTLINGER   不關心     優雅          否
  SO_LINGER             零            強制          否
  SO_LINGER            非零         優雅          是

 

http://blog.csdn.net/fullsail/article/details/4424324

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM