0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

為什么要有TIME_WAIT狀態(tài)

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-13 11:26 ? 次閱讀

首先我們說下狀態(tài) TIME_WAIT 出現(xiàn)的原因

TCP的新建連接,斷開連接的流程和各個狀態(tài),如下圖所示

圖片

由上圖可知:TIME_WAIT 是主動斷開連接的一方會出現(xiàn)的,客戶端,服務(wù)器都有可能出現(xiàn)

當(dāng)客戶端主動斷開連接時,發(fā)出最后一個ACK后就會處于 TIME_WAIT狀態(tài)

當(dāng)服務(wù)器主動斷開連接時,發(fā)出最后一個ACK后就會處于 TIME_WAIT狀態(tài)

結(jié)論:TIME_WAIT 是必然會出現(xiàn)的狀態(tài),是正?,F(xiàn)象,且會定時回收

TIME_WAIT 狀態(tài)持續(xù)2MSL時間,MSL就是maximum segment lifetime(最大報文段的生命期),這是一個IP數(shù)據(jù)包能在互聯(lián)網(wǎng)上生存的最長時間,超過這個時間將在網(wǎng)絡(luò)中消失(被丟棄)。RFC 793中規(guī)定MSL為2分鐘,實際應(yīng)用中,可能為30S,1分鐘,2分鐘。

我的系統(tǒng)是ubuntu,輸入如下命令后可以看到,時間為60秒

圖片

請注意兩個狀態(tài),一個是TIME_WAIT,一個是CLOSE_WAIT,完全不同的兩個狀態(tài)

TIME_WAIT 出現(xiàn)在主動斷開方,發(fā)出最后一個ACK后

CLOSE_WAIT 出現(xiàn)在被動斷開方,收到主動斷開方的FIN,發(fā)出自己的ACK后

問題:為什么要有TIME_WAIT狀態(tài)?

  1. 為了可靠地關(guān)閉TCP連接

舉例:我們把主動斷開連接的一方稱為C端,被動斷開連接的一方稱為S端,由于網(wǎng)絡(luò)不可靠,C端發(fā)送的最后一個ACK報文可能沒成功發(fā)送到S端,那么S端就會重新發(fā)上一個報文即FIN,如果C端處于TIME_WAIT狀態(tài)下,就可以重新發(fā)送報文ACK,然后重新計時2MSL時間才會進(jìn)入CLOSED狀態(tài),S端收到ACK后就可以正常關(guān)閉TCP連接了。反之,如果這時C端處于 CLOSED 狀態(tài) ,就會響應(yīng) RST報文而不是ACK報文,那S端會認(rèn)為這是一個錯誤,只能異常關(guān)閉TCP連接

  1. 防止上一次連接中的包,迷路后重新出現(xiàn),影響新連接

由于網(wǎng)絡(luò)的不可靠,TCP分節(jié)可能因為路由器異常而“迷途”,在迷途期間,TCP發(fā)送端會因確認(rèn)超時而重發(fā)這個分節(jié),這個分節(jié)最終被發(fā)送到對方時,對方可能已經(jīng)是一個新的連接了,由此造成混亂。舉例:關(guān)閉一個TCP鏈接后,馬上又創(chuàng)建了一個相同的IP地址和端口之間的TCP鏈接,后一個鏈接被稱為前一個鏈接的化身(incarnation),那么此時有可能出現(xiàn)這種狀況,前一個鏈接的迷途重復(fù)分節(jié)在前一個鏈接終止后出現(xiàn)了,從而被誤解成從屬于新的連接的數(shù)據(jù)。為了不出現(xiàn)這種混亂,TCP不容許處于TIME_WAIT狀態(tài)的連接立即啟動一個新連接,由于TIME_WAIT狀態(tài)持續(xù)2MSL,就能夠保證當(dāng)成功創(chuàng)建一個TCP鏈接的時候,來自前一個連接的迷途重復(fù)分節(jié)已經(jīng)在網(wǎng)絡(luò)中消逝

注意close() 和 shutdown()的區(qū)別

close()其實只是將socket fd的引用計數(shù)減1,只有當(dāng)該socket fd的引用計數(shù)減至0時,TCP傳輸層才會發(fā)起4次握手從而真正關(guān)閉連接。而shutdown則可以直接發(fā)起關(guān)閉連接所需的4次握手,而不用受到引用計數(shù)的限制

close()會終止TCP的雙工鏈路。由于TCP連接的全雙工特性,可能會存在這樣的應(yīng)用場景:local peer不會再向remote peer發(fā)送數(shù)據(jù),而remote peer可能還有數(shù)據(jù)需要發(fā)送過來,在這種情況下,如果local peer想要通知remote peer自己不會再發(fā)送數(shù)據(jù)但還會繼續(xù)收數(shù)據(jù)這個事實,用close()是不行的,而shutdown()可以完成這個任務(wù)

服務(wù)器短時間內(nèi)大量的TIME_WAIT出現(xiàn),才是問題

會引發(fā)以下問題

  1. 由于處于TIME_WAIT狀態(tài),連接并未關(guān)閉,占據(jù)了大量的CPU,內(nèi)存,文件描述符等,造成新的連接無法建立,客戶端表現(xiàn)就是連接失敗
  2. 如果服務(wù)器上同時有nginx,且nginx由于反向代理,那么還會占用很多端口(S端處于TIME_WAIT,該連接的另一方即C端需獨占一個端口,C端是由nginx代理建立的),要知道端口是有限的,最多65535,一旦端口占用完,無論服務(wù)器配置如何高,新連接都無法建立了,客戶端表現(xiàn)仍然是連接失敗

短時間內(nèi)大量TIME_WAIT出現(xiàn)的根本原因:高并發(fā)且持續(xù)的短連接

  1. 業(yè)務(wù)上使用了持續(xù)且大量的短連接,純屬設(shè)計缺陷,例如爬蟲服務(wù)器就有可能出現(xiàn)這樣的問題
  2. http請求中connection的值被設(shè)置成close,因為服務(wù)器處理完http請求后會主動斷開連接,然后這個連接就處于TIME_WAIT狀態(tài)了。持續(xù)時間長且量級較大的話,問題就顯現(xiàn)出來了。http洗衣1.0中,connection默認(rèn)為close,但在http1.1中connection默認(rèn)行為是keep-alive,就是因為這個原因
  3. 服務(wù)器被攻擊了,攻擊方采用了大量的短連接

重點:解決辦法

  1. 代碼層修改,把短連接改為長連接,但代價較大
  2. 修改 ip_local_port_range,增大可用端口范圍,比如1024 ~ 65535
  3. 客戶端程序中設(shè)置socket的 SO_LINGER 選項
  4. 打開 tcp_tw_recycle 和tcp_timestamps 選項,有一定風(fēng)險,且linux4.12之后被廢棄
  5. 打開 tcp_tw_reuse 和 tcp_timestamps 選項
  6. 設(shè)置 tcp_max_tw_buckets 為一個較小的值

下面我們開始對各個辦法進(jìn)行詳細(xì)講解

辦法1:代碼層修改,把短連接改為長連接

由于TIME_WAIT出現(xiàn)的根本原因是高并發(fā)且持續(xù)的短連接,所以如果能把短連接改成長連接,就能徹底解決問題。比如http請求中的connection設(shè)置為keep-alive。只是代碼層的修改往往會比較大,不再啰嗦

辦法2. 修改 ip_local_port_range,增大可用端口范圍

我這里linux系統(tǒng)是ubuntu,輸入如下命令可查看可用的端口范圍

圖片

默認(rèn)差不多有3萬個,我們可以修改這個值,但是注意最小不能小于1024,最大不能大于65535,也就是說改完之后最多有6萬多個可用端口

只是一般線上遇到大量的TIME_WAIT,都是高并發(fā)且持續(xù)的短連接,單純擴(kuò)大端口范圍并不能從根本上解決問題,只是能多撐一會兒

辦法3. 客戶端程序中設(shè)置socket的 SO_LINGER 選項

SO_LINGER 選項可以用來控制調(diào)用close函數(shù)關(guān)閉連接后的行為,linger的定義如下

struct linger {
     int l_onoff; /* 0 = off, nozero = on */
     int l_linger; /* linger time */

有三種情況

  1. 設(shè)置 l_onoff 為0,l_linger的值會被忽略,也是內(nèi)核缺省的情況,和不設(shè)置沒區(qū)別。close調(diào)用會立即返回給調(diào)用者,TCP模塊負(fù)責(zé)嘗試發(fā)送殘留的緩沖區(qū)數(shù)據(jù),會經(jīng)過通常四分組終止序列(FIN/ACK/FIN/ACK),不能解決任何問題
  2. 設(shè)置 l_onoff 為1,l_linger為0,則連接立即終止,TCP將丟棄殘留在發(fā)送緩沖區(qū)中的任何數(shù)據(jù)并發(fā)送一個RST報文給對方,而不是通常的四分組終止序列。對方收到RST報文后直接進(jìn)入CLOSED狀態(tài),從根本上避免了TIME_WAIT狀態(tài)
  3. 設(shè)置 l_onoff 為1,l_linger > 0,有兩種情況

a. 如果socket為阻塞的,則close將阻塞等待l_linger 秒的時間。如果在l_linger秒時間內(nèi)TCP模塊成功發(fā)送完殘留在緩沖區(qū)的數(shù)據(jù),則close返回0,表示成功。如果l_linger時間內(nèi)TCP模塊沒有成功發(fā)送殘留的緩沖區(qū)數(shù)據(jù),則close返回-1,表示失敗,并將errno設(shè)置為EWOULDBLOCK

b. 如果socket為非阻塞的,那么close立即返回,此時需要根據(jù)close返回值以及errno來判斷TCP模塊是否成功發(fā)送殘留在緩沖區(qū)的數(shù)據(jù)

第3中情況,其實就是第1種和第2種的折中處理,且當(dāng)socket為非阻塞的場景下是沒有作用的

綜上所述:第2種情況,也就是l_onoff為1,l_linger不為0,可以用于解決服務(wù)器大量TIME_WAIT的問題

只是Linux上測試的時候,并未發(fā)現(xiàn)發(fā)送了RST報文,而是正常進(jìn)行了四步關(guān)閉流程,

初步推斷是“只有在丟棄數(shù)據(jù)的時候才發(fā)送RST”,如果沒有丟棄數(shù)據(jù),則走正常的關(guān)閉流程

查看Linux源碼,確實有這么一段注釋和源碼

/* As outlined in RFC 2525, section 2.17, we send a RST here because
* data was lost. To witness the awful effects of the old behavior of
* always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
* GET in an FTP client, suspend the process, wait for the client to
* advertise a zero window, then kill -9 the FTP client, wheee...
* Note: timeout is always zero in such a case.
*/
if (data_was_unread) {
    /* Unread data was tossed, zap the connection. */
    NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
    tcp_set_state(sk, TCP_CLOSE);
    tcp_send_active_reset(sk, sk- >sk_allocation);
}

從原理上來說,這個選項有一定的危險性,可能導(dǎo)致丟數(shù)據(jù),使用的時候要小心一些

從實測情況來看,打開這個選項后,服務(wù)器TIME_WAIT連接數(shù)為0,且不受網(wǎng)絡(luò)組網(wǎng)(例如是否虛擬機(jī)等)的影響

辦法4. 打開 tcp_tw_recycle 和tcp_timestamps 選項,有一定風(fēng)險,且linux4.12之后被廢棄

官方文檔中解釋如下:

tcp_tw_recycle 選項作用為:Enable fast recycling TIME-WAIT sockets. Default value is 0.

tcp_timestamps 選項作用為:Enable timestamps as defined in RFC1323. Default value is 1

這兩個選項是linux內(nèi)核提供的控制選項,和具體的應(yīng)用程序沒有關(guān)系,而且網(wǎng)上也能夠查詢到大量的相關(guān)資料,但信息都不夠完整,最主要的幾個問題如下;

1)快速回收到底有多快?

2)有的資料說只要打開tcp_tw_recycle即可,有的又說要tcp_timestamps同時打開,到底是哪個正確?

3)為什么從虛擬機(jī)NAT出去發(fā)起客戶端連接時選項無效,非虛擬機(jī)連接就有效?為了搞清楚上面的疑問,只能看代碼,看出一些相關(guān)的代碼供大家參考:

=====linux-2.6.37 net/ipv4/tcp_minisocks.c 269======

void tcp_time_wait(struct sock *sk, int state, int timeo)
{
    struct inet_timewait_sock *tw = NULL;
    const struct inet_connection_sock *icsk = inet_csk(sk);
    const struct tcp_sock *tp = tcp_sk(sk);
    int recycle_ok = 0;


    // 判斷是否快速回收,這里可以看出tcp_tw_recycle和tcp_timestamps兩個選項都打開的時候才進(jìn)行快速回收,
    //且還有進(jìn)一步的判斷條件,后面會分析,這個進(jìn)一步的判斷條件和第三個問題有關(guān)
    if (tcp_death_row.sysctl_tw_recycle && tp- >rx_opt.ts_recent_stamp)
        recycle_ok = icsk- >icsk_af_ops- >remember_stamp(sk);


    if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
        tw = inet_twsk_alloc(sk, state);


    if (tw != NULL) {
        struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
        //計算快速回收的時間,等于 RTO * 3.5,回答第一個問題的關(guān)鍵是RTO(RetransmissionTimeout)大概是多少
        const int rto = (icsk- >icsk_rto < < 2) - (icsk- >icsk_rto > > 1);

        //。。。。。。此處省略很多代碼。。。。。。

    if (recycle_ok) 
    {
        //設(shè)置快速回收的時間
        tw- >tw_timeout = rto;
    } 
    else 
    {
        tw- >tw_timeout = TCP_TIMEWAIT_LEN;
        if (state == TCP_TIME_WAIT)
            timeo = TCP_TIMEWAIT_LEN;
    }

    //。。。。。。此處省略很多代碼。。。。。。
}

這里講下RTO(Retransmission Time Out):重傳超時時間,即從數(shù)據(jù)發(fā)送時刻算起,超過這個時間便執(zhí)行重傳

RFC中有關(guān)于RTO計算的詳細(xì)規(guī)定,一共有三個:RFC-793、RFC-2988、RFC-6298,Linux的實現(xiàn)是參考RFC-2988。

對于這些算法的規(guī)定和Linux的實現(xiàn),有興趣的同學(xué)可以自己深入研究,實際應(yīng)用中我們只要記住Linux如下兩個邊界值:

=====linux-2.6.37 net/ipv4/tcp.c 126================

#define TCP_RTO_MAX ((unsigned)(120*HZ))

#define TCP_RTO_MIN ((unsigned)(HZ/5))

==========================================

這里的HZ是1s,因此可以得出RTO最大是120s,最小是200ms,對于局域網(wǎng)的機(jī)器來說,正常情況下RTO基本上就是200ms,因此3.5 RTO就是700ms

也就是說,快速回收是TIME_WAIT的狀態(tài)持續(xù)700ms,而不是正常的2MSL

實測結(jié)果也驗證了這個推論,不停的查看TIME_WAIT狀態(tài)的連接,偶爾能看到1個

最后一個問題是為什么從虛擬機(jī)發(fā)起的連接即使設(shè)置了tcp_tw_recycle和tcp_timestamps,也不會快速回收,繼續(xù)看代碼:

tcp_time_wait函數(shù)中的代碼行:recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);對應(yīng)的實現(xiàn)如下:

=====linux-2.6.37 net/ipv4/tcp_ipv4.c 1772=====

int tcp_v4_remember_stamp(struct sock *sk)
{
    //。。。。。。此處省略很多代碼。。。。。。

    //當(dāng)獲取對端信息時,進(jìn)行快速回收,否則不進(jìn)行快速回收
    if (peer) 
    {
        if ((s32)(peer- >tcp_ts - tp- >rx_opt.ts_recent) <= 0 ||
           ((u32)get_seconds() - peer- >tcp_ts_stamp > TCP_PAWS_MSL &&
            peer- >tcp_ts_stamp <= (u32)tp- >rx_opt.ts_recent_stamp)) 
        {
            peer- >tcp_ts_stamp = (u32)tp- >rx_opt.ts_recent_stamp;
            peer- >tcp_ts = tp- >rx_opt.ts_recent;
        }

        if (release_it)
            inet_putpeer(peer);
        return 1;
    }

    return 0;
}

上面這段代碼應(yīng)該就是測試的時候虛擬機(jī)環(huán)境不會釋放的原因,當(dāng)使用虛擬機(jī)NAT出去的時候,服務(wù)器無法獲取隱藏在NAT后的機(jī)器信息。

生產(chǎn)環(huán)境也出現(xiàn)了設(shè)置了選項,但TIME_WAIT連接數(shù)達(dá)到4W多的現(xiàn)象,可能和虛擬機(jī)有關(guān),也可能和組網(wǎng)有關(guān)。

總結(jié)一下:

1)快速回收到底有多快?

答:局域網(wǎng)環(huán)境下,700ms就回收

2)有的資料說只要打開tcp_tw_recycle即可,有的又說要tcp_timestamps同時打開,到底是哪個正確?

答:需要同時打開,但默認(rèn)情況下tcp_timestamps就是打開的,所以會有人說只要打開tcp_tw_recycle即可

3)為什么從虛擬機(jī)發(fā)起客戶端連接時選項無效,非虛擬機(jī)連接就有效?

答:和網(wǎng)絡(luò)組網(wǎng)有關(guān)系,無法獲取對端信息時就不進(jìn)行快速回收。

注意1

NAT環(huán)境下,打開 tcp_tw_recycle選項可能會引發(fā)其他問題,tcp_tw_recycle是依賴tcp_timestamps參數(shù)的。例如辦公室的外網(wǎng)地址只有一個,所有人訪問后臺都會通過路由器做SNAT將內(nèi)網(wǎng)地址映射為公網(wǎng)IP,由于服務(wù)端和客戶端都啟用了tcp_timestamps,因此TCP頭部中增加時間戳信息,而在服務(wù)器看來,同一客戶端的時間戳必然是線性增長的,但是,由于我的客戶端網(wǎng)絡(luò)環(huán)境是NAT,因此每臺主機(jī)的時間戳都是有差異的,在啟用tcp_tw_recycle后,一旦有客戶端斷開連接,服務(wù)器可能就會丟棄那些時間戳較小的客戶端的SYN包,這也就導(dǎo)致了網(wǎng)站訪問極不穩(wěn)定。

簡單來說就是,Linux會丟棄所有來自遠(yuǎn)端的timestramp時間戳小于上次記錄的時間戳(由同一個遠(yuǎn)端發(fā)送的)的任何數(shù)據(jù)包。也就是說要使用該選項,則必須保證數(shù)據(jù)包的時間戳是單調(diào)遞增的。同時從4.10內(nèi)核開始,官方修改了時間戳的生成機(jī)制,所以導(dǎo)致 tcp_tw_recycle 和新時間戳機(jī)制工作在一起不那么友好,同時 tcp_tw_recycle 幫助也不那么的大。

此處的時間戳并不是我們通常意義上面的絕對時間,而是一個相對時間。很多情況下,我們是沒法保證時間戳單調(diào)遞增的,比如業(yè)務(wù)服務(wù)器之前部署了NAT,LVS等情況。相信很多小伙伴上班的公司大概率實用實用各種公有云,而各種公有云的 LVS 網(wǎng)關(guān)都是 FullNAT 。所以可能導(dǎo)致在高并發(fā)的情況下,莫名其妙的 TCP 建聯(lián)不是那么順暢或者丟連接

主機(jī)A SIP:P1 (時間戳T0) —> Server

主機(jī)A斷開后

主機(jī)B SIP:P1 (時間戳T1) T1 < T0 —> Server 丟棄

注意2

在linux內(nèi)核版本從4.12之后,tcp_tw_recycle已經(jīng)被廢棄了

我的linux機(jī)器是ubuntu,查看內(nèi)核版本如下

圖片

linux 內(nèi)核版本已經(jīng)4.15了,如果開發(fā)tcp_tw_recycle,執(zhí)行命令刷新的話,就會有如下報錯

圖片

提示得很明確,這個文件不存在

sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory

綜上

可以看出這種方法不是很保險,在實際應(yīng)用中可能受到虛擬機(jī)、網(wǎng)絡(luò)組網(wǎng)、防火墻之類的影響從而導(dǎo)致不能進(jìn)行快速回收。

辦法5. 打開tcp_tw_reuse和tcp_timestamps選項

官方文檔中解釋如下:

tcp_tw_recycle選項:Allow to reuse TIME-WAIT sockets for new connections when it is

safe from protocol viewpoint. Default value is 0

這里的關(guān)鍵在于“協(xié)議什么情況下認(rèn)為是安全的”,由于環(huán)境限制,沒有辦法進(jìn)行驗證,通過看源碼簡單分析了一下

=====linux-2.6.37 net/ipv4/tcp_ipv4.c 114=====

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
{
    const struct tcp_timewait_sock *tcptw = tcp_twsk(sktw);
    struct tcp_sock *tp = tcp_sk(sk);


    /* With PAWS, it is safe from the viewpoint
      of data integrity. Even without PAWS it is safe provided sequence
      spaces do not overlap i.e. at data rates <= 80Mbit/sec.
      Actually, the idea is close to VJ's one, only timestamp cache is
      held not per host, but per port pair and TW bucket is used as state
      holder.
      If TW bucket has been already destroyed we fall back to VJ's scheme
      and use initial timestamp retrieved from peer table.
    */

    //從代碼來看,tcp_tw_reuse選項和tcp_timestamps選項也必須同時打開;否則tcp_tw_reuse就不起作用
    //另外,所謂的“協(xié)議安全”,從代碼來看應(yīng)該是收到最后一個包后超過1s
    if (tcptw- >tw_ts_recent_stamp &&
       (twp == NULL || (sysctl_tcp_tw_reuse &&
        get_seconds() - tcptw- >tw_ts_recent_stamp > 1))) 
    {
        tp- >write_seq = tcptw- >tw_snd_nxt + 65535 + 2;
        if (tp- >write_seq == 0)
            tp- >write_seq = 1;
        tp- >rx_opt.ts_recent  = tcptw- >tw_ts_recent;
        tp- >rx_opt.ts_recent_stamp = tcptw- >tw_ts_recent_stamp;
        sock_hold(sktw);
        return 1;
    }

    return 0;
}

總結(jié)一下:

  1. tcp_tw_reuse選項和tcp_timestamps選項也必須同時打開;
  2. 重用TIME_WAIT的條件是收到最后一個包后超過1s。

官方手冊有一段警告:

It should not be changed without advice/request of technical experts.

對于大部分局域網(wǎng)或者公司內(nèi)網(wǎng)應(yīng)用來說,滿足條件都是沒有問題的,因此官方手冊里面的警告其實也沒那么可怕

辦法6:設(shè)置tcp_max_tw_buckets為一個較小的值,要比可用端口范圍小,比如可用端口范圍為6萬,這個值可以設(shè)置為5.5萬

tcp_max_tw_buckets - INTEGER

官方文檔解釋如下

Maximal number of timewait sockets held by system simultaneously. If this number is exceeded time-wait socket is immediately destroyed and warning is printed.

翻譯一下:內(nèi)核持有的狀態(tài)為TIME_WAIT的最大連接數(shù)。如果超過這個數(shù)字,新的TIME_WAIT的連接會被立即銷毀,并打印警告

官方文檔沒有說明默認(rèn)值,通過幾個系統(tǒng)的簡單驗證,初步確定默認(rèn)值是180000

源碼如下

void tcp_time_wait(struct sock *sk, int state, int timeo)
{
    struct inet_timewait_sock *tw = NULL;
    const struct inet_connection_sock *icsk = inet_csk(sk);
    const struct tcp_sock *tp = tcp_sk(sk);
    int recycle_ok = 0;

    if (tcp_death_row.sysctl_tw_recycle && tp- >rx_opt.ts_recent_stamp)
        recycle_ok = icsk- >icsk_af_ops- >remember_stamp(sk);

    // 這里判斷TIME_WAIT狀態(tài)的連接數(shù)是否超過上限
    if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
        tw = inet_twsk_alloc(sk, state);

    if (tw != NULL) 
    {
        //分配成功,進(jìn)行TIME_WAIT狀態(tài)處理,此處略去很多代碼
    }   
    else 
    {
        //分配失敗,不進(jìn)行處理,只記錄日志: TCP: time wait bucket table overflow
        /* Sorry, if we're out of memory, just CLOSE this
        * socket up.  We've got bigger problems than
        * non-graceful socket closings.
        */
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW);
    }

    tcp_update_metrics(sk);
    tcp_done(sk);
}

官方手冊中有一段警告:

This limit exists only to prevent simple DoS attacks, you must not lower the limit artificially,

but rather increase it (probably, after increasing installed memory), if network conditions require more than default value.

基本意思是這個用于防止Dos攻擊,我們不應(yīng)該人工減少,如果網(wǎng)絡(luò)條件需要的話,反而應(yīng)該增加。

但其實對于我們的局域網(wǎng)或者公司內(nèi)網(wǎng)應(yīng)用來說,這個風(fēng)險并不大。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • IP
    IP
    +關(guān)注

    關(guān)注

    5

    文章

    1613

    瀏覽量

    149255
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1347

    瀏覽量

    78934
  • TIME
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    14312
  • 流程
    +關(guān)注

    關(guān)注

    0

    文章

    4

    瀏覽量

    3592
收藏 人收藏

    評論

    相關(guān)推薦

    Java中sleep和wait的區(qū)別

    。  wait()是線程交互時,如果線程對一個同步對象x 發(fā)出一個wait()調(diào)用,該線程會暫停執(zhí)行,被調(diào)對象進(jìn)入等待狀態(tài),直到被喚醒或等待時間到。  當(dāng)調(diào)用wait()后,線程會釋放
    發(fā)表于 11-25 11:50

    CC3200 socket狀態(tài)如何查詢?

    已,正在等待本地套接字的關(guān)閉確認(rèn) FIN_WAIT_2 套接字已關(guān)閉,正在等待遠(yuǎn)程套接字關(guān)閉TIME_WAIT 這個套接字已經(jīng)關(guān)閉,正在等待遠(yuǎn)程套接字的關(guān)閉傳送
    發(fā)表于 05-06 11:00

    WEB CLOSE_WAIT socket不釋放如何解決呢

    :web連接過后發(fā)現(xiàn)有大量的TIME_WAIT狀態(tài)的socket,怎么限制WEB的并發(fā)數(shù)量,把rtConfig.h中的這個宏改小到多少合適呢?如果太小了會不會導(dǎo)致web登錄不了的情況?#define WEBNET_CONN_MAX 8
    發(fā)表于 09-27 10:06

    什么是TIME

    什么是TIME  英文原義:Time Server Protocol 中文釋義:標(biāo)準(zhǔn)時間服務(wù)器協(xié)議 注  解:這
    發(fā)表于 02-23 11:25 ?932次閱讀

    建立時間和保持時間(setup time 和 hold time

    建立時間和保持時間貫穿了整個時序分析過程。只要涉及到同步時序電路,那么必然有上升沿、下降沿采樣,那么無法避免setup-time 和 hold-time這兩個概念。 1. 什么是setup-time
    發(fā)表于 02-08 14:48 ?5964次閱讀

    分析在java中sleep和wait的不同

    的監(jiān)控狀態(tài)依然保持者,當(dāng)指定的時間到了又會自動恢復(fù)運行狀態(tài)。 在調(diào)用sleep()方法的過程中,線程不會釋放對象鎖。 而當(dāng)調(diào)用wait()方法的時候,線程會放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象調(diào)用notify(
    發(fā)表于 09-27 14:41 ?0次下載

    服務(wù)器產(chǎn)生大量的TIME_WAIT究竟是因為什么

    寫在開頭,大概 4 年前,聽到運維同學(xué)提到 TIME_WAIT 狀態(tài)的 TCP 連接過多的問題,但是當(dāng)時沒有去細(xì)琢磨;最近又聽人說起,是一個新手進(jìn)行壓測過程中,遇到的問題,因此,花點時間,細(xì)深究一下
    的頭像 發(fā)表于 10-13 16:47 ?1.4w次閱讀
    服務(wù)器產(chǎn)生大量的<b class='flag-5'>TIME_WAIT</b>究竟是因為什么

    請問一下RPB是干啥用的

    注意:同一網(wǎng)段內(nèi)的所有節(jié)點,對應(yīng)的CANNM_MSG_CYCLE_TIME、CANNM_REPEAT_MESSAGE_TIME、CANNM_WAIT_BUS_SLEEP_TIME、NM-TIM
    的頭像 發(fā)表于 08-30 10:19 ?5777次閱讀
    請問一下RPB是干啥用的

    學(xué)習(xí)Linux命令的正確姿勢

    短時間后,所有的 TIME_WAIT 全都消失,被回收,端口包括服務(wù),均正常。即,在高并發(fā)的場景下,TIME_WAIT 連接存在,屬于正常現(xiàn)象。
    的頭像 發(fā)表于 08-31 10:27 ?476次閱讀

    WAiT:野生動物追蹤器

    電子發(fā)燒友網(wǎng)站提供《WAiT:野生動物追蹤器.zip》資料免費下載
    發(fā)表于 10-31 09:38 ?3次下載
    <b class='flag-5'>WAiT</b>:野生動物追蹤器

    圖解Java多線程中的wait()和notify()方法

    wait()和notify()是Object類的方法,用于線程的等待與喚醒,必須搭配synchronized 鎖來使用。
    的頭像 發(fā)表于 03-22 09:29 ?2578次閱讀

    KUKA機(jī)器人WAIT FOR運用條件

    WAIT FOR … : 等至條件已滿足 WAITFOR 停止程序,直到已滿足特定的條件。然后程序繼續(xù)運行。WAIT FOR 將觸發(fā)預(yù)進(jìn)停止。 編譯器識別不到由于錯誤的表達(dá)而使表達(dá)式無法采用數(shù)值
    的頭像 發(fā)表于 06-13 11:31 ?3047次閱讀

    TCP和UDP分別是什么 TCP和UDP協(xié)議各有什么特點

    在 TCP 四次揮手的最后一步,客戶端進(jìn)入 TIME_WAIT 狀態(tài),需要等待一段時間再進(jìn)入 CLOSED 狀態(tài)。等待時間通常是兩個最大報文段生命周期,即 2MSL,這是為了確保服務(wù)器端能夠收到客戶端發(fā)送的最后一個 ACK 報文
    的頭像 發(fā)表于 08-09 12:34 ?4264次閱讀

    TIME_WAIT狀態(tài)的優(yōu)化思路

    為什么需要TIME_WAIT狀態(tài)?為什么TIME_WAIT的時長是2*MSL? 原因1:防止連接關(guān)閉時四次揮手中的最后一次ACK丟失: TCP需要保證每一包數(shù)據(jù)都可靠的到達(dá)對端,包括正常連接
    的頭像 發(fā)表于 11-10 10:44 ?516次閱讀

    TIME_WAIT是什么

    ,遇到了這道題目: 生產(chǎn)環(huán)境 Nginx 后端服務(wù)大量 TIME-WAIT 的解決步驟 這里小編給大家做一下系統(tǒng)化、體系化的梳理,使得大家可以充分展示一下大家雄厚的 “技術(shù)肌肉”,讓面試官愛到 “不能自已、口水直流”。 基礎(chǔ)知識 TIME_WAIT是什么? 在構(gòu)建TCP客
    的頭像 發(fā)表于 11-10 14:48 ?607次閱讀
    <b class='flag-5'>TIME_WAIT</b>是什么