TCP連接狀態(tài)詳解及TIME_WAIT過多的解決方法[轉(zhuǎn)]

TIME_WAIT狀態(tài)原理


通信雙方建立TCP連接后呐赡,主動關(guān)閉連接的一方就會進入TIME_WAIT狀態(tài)倾芝。

客戶端主動關(guān)閉連接時,會發(fā)送最后一個ack后订框,然后會進入TIME_WAIT狀態(tài)析苫,再停留2個MSL時間(后有MSL的解釋),進入CLOSED狀態(tài)穿扳。

下圖是以客戶端主動關(guān)閉連接為例藤违,說明這一過程的。

揮手過程

TIME_WAIT狀態(tài)存在的理由
TCP/IP協(xié)議就是這樣設計的纵揍,是不可避免的顿乒。主要有兩個原因:

1)可靠地實現(xiàn)TCP全雙工連接的終止
TCP協(xié)議在關(guān)閉連接的四次握手過程中,最終的ACK是由主動關(guān)閉連接的一端(后面統(tǒng)稱A端)發(fā)出的泽谨,如果這個ACK丟失璧榄,對方(后面統(tǒng)稱B端)將重發(fā)出最終的FIN特漩,因此A端必須維護狀態(tài)信息(TIME_WAIT)允許它重發(fā)最終的ACK。如果A端不維持TIME_WAIT狀態(tài)骨杂,而是處于CLOSED 狀態(tài)涂身,那么A端將響應RST分節(jié),B端收到后將此分節(jié)解釋成一個錯誤(在java中會拋出connection reset的SocketException)搓蚪。

因而蛤售,要實現(xiàn)TCP全雙工連接的正常終止,必須處理終止過程中四個分節(jié)任何一個分節(jié)的丟失情況妒潭,主動關(guān)閉連接的A端必須維持TIME_WAIT狀態(tài) 悴能。

2)允許老的重復分節(jié)在網(wǎng)絡中消逝

TCP分節(jié)可能由于路由器異常而“迷途”,在迷途期間雳灾,TCP發(fā)送端可能因確認超時而重發(fā)這個分節(jié)漠酿,迷途的分節(jié)在路由器修復后也會被送到最終目的地,這個遲到的迷途分節(jié)到達時可能會引起問題谎亩。在關(guān)閉“前一個連接”之后炒嘲,馬上又重新建立起一個相同的IP和端口之間的“新連接”,“前一個連接”的迷途重復分組在“前一個連接”終止后到達匈庭,而被“新連接”收到了夫凸。為了避免這個情況,TCP協(xié)議不允許處于TIME_WAIT狀態(tài)的連接啟動一個新的可用連接阱持,因為TIME_WAIT狀態(tài)持續(xù)2MSL夭拌,就可以保證當成功建立一個新TCP連接的時候,來自舊連接重復分組已經(jīng)在網(wǎng)絡中消逝紊选。

MSL時間
MSL就是maximum segment lifetime(最大分節(jié)生命期)啼止,這是一個IP數(shù)據(jù)包能在互聯(lián)網(wǎng)上生存的最長時間,超過這個時間IP數(shù)據(jù)包將在網(wǎng)絡中消失 兵罢。MSL在RFC 1122上建議是2分鐘献烦,而源自berkeley的TCP實現(xiàn)傳統(tǒng)上使用30秒。

TIME_WAIT狀態(tài)維持時間
TIME_WAIT狀態(tài)維持時間是兩個MSL時間長度卖词,也就是在1-4分鐘巩那。Windows操作系統(tǒng)就是4分鐘。

http://www.cnblogs.com/itcomputer/p/7150954.html

上圖對排除和定位網(wǎng)絡或系統(tǒng)故障時大有幫助此蜈,但是怎樣牢牢地將這張圖刻在腦中呢即横?那么你就一定要對這張圖的每一個狀態(tài),及轉(zhuǎn)換的過程有深刻地認識裆赵,不能只停留在一知半解之中东囚。下面對這張圖的11種狀態(tài)詳細解釋一下,以便加強記憶战授!不過在這之前页藻,先回顧一下TCP建立連接的三次握手過程桨嫁,以及關(guān)閉連接的四次握手過程。

1份帐、建立連接協(xié)議(三次握手)
(1)客戶端發(fā)送一個帶SYN標志的TCP報文到服務器璃吧。這是三次握手過程中的報文1。
(2) 服務器端回應客戶端的废境,這是三次握手中的第2個報文畜挨,這個報文同時帶ACK標志和SYN標志。因此它表示對剛才客戶端SYN報文的回應噩凹;同時又標志SYN給客戶端巴元,詢問客戶端是否準備好進行數(shù)據(jù)通訊。
(3) 客戶必須再次回應服務段一個ACK報文栓始,這是報文段3务冕。

2血当、連接終止協(xié)議(四次握手)
由于TCP連接是全雙工的幻赚,因此每個方向都必須單獨進行關(guān)閉。這原則是當一方完成它的數(shù)據(jù)發(fā)送任務后就能發(fā)送一個FIN來終止這個方向的連接臊旭。收到一個 FIN只意味著這一方向上沒有數(shù)據(jù)流動落恼,一個TCP連接在收到一個FIN后仍能發(fā)送數(shù)據(jù)。首先進行關(guān)閉的一方將執(zhí)行主動關(guān)閉离熏,而另一方執(zhí)行被動關(guān)閉佳谦。

(1) TCP客戶端發(fā)送一個FIN,用來關(guān)閉客戶到服務器的數(shù)據(jù)傳送(報文段4)滋戳。
(2) 服務器收到這個FIN钻蔑,它發(fā)回一個ACK,確認序號為收到的序號加1(報文段5)奸鸯。和SYN一樣咪笑,一個FIN將占用一個序號。
(3) 服務器關(guān)閉客戶端的連接娄涩,發(fā)送一個FIN給客戶端(報文段6)窗怒。
(4) 客戶段發(fā)回ACK報文確認,并將確認序號設置為收到序號加1(報文段7)蓄拣。

CLOSED: 這個沒什么好說的了扬虚,表示初始狀態(tài)。
LISTEN: 這個也是非常容易理解的一個狀態(tài)球恤,表示服務器端的某個SOCKET處于監(jiān)聽狀態(tài)辜昵,可以接受連接了。
SYN_RCVD: 這個狀態(tài)表示接受到了SYN報文咽斧,在正常情況下堪置,這個狀態(tài)是服務器端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態(tài)贷洲,很短暫,基本上用netstat你是很難看到這種狀態(tài)的晋柱,除非你特意寫了一個客戶端測試程序优构,故意將三次TCP握手過程中最后一個ACK報文不予發(fā)送。因此這種狀態(tài)時雁竞,當收到客戶端的ACK報文后钦椭,它會進入到ESTABLISHED狀態(tài)。
SYN_SENT: 這個狀態(tài)與SYN_RCVD遙想呼應碑诉,當客戶端SOCKET執(zhí)行CONNECT連接時彪腔,它首先發(fā)送SYN報文,因此也隨即它會進入到了SYN_SENT狀態(tài)进栽,并等待服務端的發(fā)送三次握手中的第2個報文德挣。SYN_SENT狀態(tài)表示客戶端已發(fā)送SYN報文。
ESTABLISHED:這個容易理解了快毛,表示連接已經(jīng)建立了格嗅。
FIN_WAIT_1: 這個狀態(tài)要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態(tài)的真正含義都是表示等待對方的FIN報文唠帝。而這兩種狀態(tài)的區(qū)別是:FIN_WAIT_1狀態(tài)實際上是當SOCKET在ESTABLISHED狀態(tài)時屯掖,它想主動關(guān)閉連接,向?qū)Ψ桨l(fā)送了FIN報文襟衰,此時該SOCKET即進入到FIN_WAIT_1狀態(tài)贴铜。而當對方回應ACK報文后,則進入到FIN_WAIT_2狀態(tài)瀑晒,當然在實際的正常情況下绍坝,無論對方何種情況下,都應該馬上回應ACK報文苔悦,所以FIN_WAIT_1狀態(tài)一般是比較難見到的轩褐,而FIN_WAIT_2狀態(tài)還有時常常可以用netstat看到间坐。
FIN_WAIT_2:上面已經(jīng)詳細解釋了這種狀態(tài)灾挨,實際上FIN_WAIT_2狀態(tài)下的SOCKET,表示半連接竹宋,也即有一方要求close連接劳澄,但另外還告訴對方,我暫時還有點數(shù)據(jù)需要傳送給你蜈七,稍后再關(guān)閉連接秒拔。
TIME_WAIT: 表示收到了對方的FIN報文,并發(fā)送出了ACK報文飒硅,就等2MSL后即可回到CLOSED可用狀態(tài)了砂缩。如果FIN_WAIT_1狀態(tài)下作谚,收到了對方同時帶FIN標志和ACK標志的報文時,可以直接進入到TIME_WAIT狀態(tài)庵芭,而無須經(jīng)過FIN_WAIT_2狀態(tài)妹懒。
注:MSL(最大分段生存期)指明TCP報文在Internet上最長生存時間,每個具體的TCP實現(xiàn)都必須選擇一個確定的MSL值.RFC 1122建議是2分鐘,但BSD傳統(tǒng)實現(xiàn)采用了30秒.TIME_WAIT 狀態(tài)最大保持時間是2 * MSL,也就是1-4分鐘.
CLOSING: 這種狀態(tài)比較特殊,實際情況中應該是很少見双吆,屬于一種比較罕見的例外狀態(tài)眨唬。正常情況下,當你發(fā)送FIN報文后好乐,按理來說是應該先收到(或同時收到)對方的ACK報文匾竿,再收到對方的FIN報文。但是CLOSING狀態(tài)表示你發(fā)送FIN報文后蔚万,并沒有收到對方的ACK報文岭妖,反而卻也收到了對方的FIN報文。什么情況下會出現(xiàn)此種情況呢反璃?其實細想一下昵慌,也不難得出結(jié)論:那就是如果雙方幾乎在同時close一個SOCKET的話,那么就出現(xiàn)了雙方同時發(fā)送FIN報文的情況版扩,也即會出現(xiàn)CLOSING狀態(tài)废离,表示雙方都正在關(guān)閉SOCKET連接侄泽。
CLOSE_WAIT: 這種狀態(tài)的含義其實是表示在等待關(guān)閉礁芦。怎么理解呢?當對方close一個SOCKET后發(fā)送FIN報文給自己悼尾,你系統(tǒng)毫無疑問地會回應一個ACK報文給對方柿扣,此時則進入到CLOSE_WAIT狀態(tài)。接下來呢闺魏,實際上你真正需要考慮的事情是察看你是否還有數(shù)據(jù)發(fā)送給對方未状,如果沒有的話,那么你也就可以close這個SOCKET析桥,發(fā)送FIN報文給對方司草,也即關(guān)閉連接。所以你在CLOSE_WAIT狀態(tài)下泡仗,需要完成的事情是等待你去關(guān)閉連接埋虹。
LAST_ACK: 這個狀態(tài)還是比較容易好理解的,它是被動關(guān)閉一方在發(fā)送FIN報文后娩怎,最后等待對方的ACK報文搔课。當收到ACK報文后,也即可以進入到CLOSED可用狀態(tài)了截亦。

最后有2個問題的回答爬泥,我自己分析后的結(jié)論(不一定保證100%正確)
1柬讨、 為什么建立連接協(xié)議是三次握手,而關(guān)閉連接卻是四次握手呢袍啡?

這是因為服務端的LISTEN狀態(tài)下的SOCKET當收到SYN報文的建連請求后踩官,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文里來發(fā)送境输。但關(guān)閉連接時卖鲤,當收到對方的FIN報文通知時,它僅僅表示對方?jīng)]有數(shù)據(jù)發(fā)送給你了畴嘶;但未必你所有的數(shù)據(jù)都全部發(fā)送給對方了蛋逾,所以你可以未必會馬上會關(guān)閉SOCKET,也即你可能還需要發(fā)送一些數(shù)據(jù)給對方之后,再發(fā)送FIN報文給對方來表示你同意現(xiàn)在可以關(guān)閉連接了窗悯,所以它這里的ACK報文和FIN報文多數(shù)情況下都是分開發(fā)送的区匣。

2、 為什么TIME_WAIT狀態(tài)還需要等2MSL后才能返回到CLOSED狀態(tài)蒋院?
這是因為:雖然雙方都同意關(guān)閉連接了亏钩,而且握手的4個報文也都協(xié)調(diào)和發(fā)送完畢,按理可以直接回到CLOSED狀態(tài)(就好比從SYN_SEND狀態(tài)到ESTABLISH狀態(tài)那樣)欺旧;但是因為我們必須要假想網(wǎng)絡是不可靠的姑丑,你無法保證你最后發(fā)送的ACK報文會一定被對方收到,因此對方處于LAST_ACK狀態(tài)下的SOCKET可能會因為超時未收到ACK報文辞友,而重發(fā)FIN報文栅哀,所以這個TIME_WAIT狀態(tài)的作用就是用來重發(fā)可能丟失的ACK報文,并保證于此称龙。

查看當前系統(tǒng)下所有連接狀態(tài)的數(shù):
[root@vps ~]#netstat -n|awk '/^tcp/{++S[$NF]}END{for (key in S) print key,S[key]}'
TIME_WAIT 286
FIN_WAIT1 5
FIN_WAIT2 6
ESTABLISHED 269
SYN_RECV 5
CLOSING 1

如發(fā)現(xiàn)系統(tǒng)存在大量TIME_WAIT狀態(tài)的連接留拾,通過調(diào)整內(nèi)核參數(shù)解決:
編輯文件/etc/sysctl.conf,加入以下內(nèi)容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后執(zhí)行 /sbin/sysctl -p 讓參數(shù)生效鲫尊。

net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies痴柔。當出現(xiàn)SYN等待隊列溢出時,啟用cookies來處理疫向,可防范少量SYN攻擊咳蔚,默認為0,表示關(guān)閉搔驼;
net.ipv4.tcp_tw_reuse = 1 表示開啟重用谈火。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0匙奴,表示關(guān)閉堆巧;
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關(guān)閉谍肤。
net.ipv4.tcp_fin_timeout 修改系默認的 TIMEOUT 時間

其它參數(shù)說明:
net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies啦租。當出現(xiàn)SYN等待隊列溢出時,啟用cookies來處理荒揣,可防范少量SYN攻擊篷角,默認為0,表示關(guān)閉系任;
net.ipv4.tcp_tw_reuse = 1 表示開啟重用恳蹲。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0俩滥,表示關(guān)閉嘉蕾;
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0霜旧,表示關(guān)閉错忱。
net.ipv4.tcp_fin_timeout = 30 表示如果套接字由本端要求關(guān)閉,這個參數(shù)決定了它保持在FIN-WAIT-2狀態(tài)的時間挂据。
net.ipv4.tcp_keepalive_time = 1200 表示當keepalive起用的時候以清,TCP發(fā)送keepalive消息的頻度。缺省是2小時崎逃,改為20分鐘掷倔。
net.ipv4.ip_local_port_range = 1024 65000 表示用于向外連接的端口范圍。缺省情況下很懈錾堋:32768到61000勒葱,改為1024到65000。
net.ipv4.tcp_max_syn_backlog = 8192 表示SYN隊列的長度障贸,默認為1024错森,加大隊列長度為8192,可以容納更多等待連接的網(wǎng)絡連接數(shù)篮洁。
net.ipv4.tcp_max_tw_buckets = 5000 表示系統(tǒng)同時保持TIME_WAIT套接字的最大數(shù)量,如果超過這個數(shù)字殃姓,TIME_WAIT套接字將立刻被清除并打印警告信息袁波。
默 認為180000,改為5000蜗侈。對于Apache篷牌、Nginx等服務器,上幾行的參數(shù)可以很好地減少TIME_WAIT套接字數(shù)量踏幻,但是對于Squid枷颊,效果卻不大。此項參數(shù)可以控制TIME_WAIT套接字的最大數(shù)量,避免Squid服務器被大量的TIME_WAIT套接字拖死夭苗。

注:
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1

設置這兩個參數(shù): reuse是表示是否允許重新應用處于TIME-WAIT狀態(tài)的socket用于新的TCP連接信卡; recyse是加速TIME-WAIT sockets回收
http://blog.sina.com.cn/s/blog_8e5d24890102w9yi.html

用于統(tǒng)計當前各種狀態(tài)的連接的數(shù)量的命令
#netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

返回結(jié)果如下:
LAST_ACK 14
SYN_RECV 348
ESTABLISHED 70
FIN_WAIT1 229
FIN_WAIT2 30
CLOSING 33
TIME_WAIT 18122

對上述結(jié)果的解釋:
CLOSED:無連接是活動的或正在進行
LISTEN:服務器在等待進入呼叫
SYN_RECV:一個連接請求已經(jīng)到達,等待確認
SYN_SENT:應用已經(jīng)開始题造,打開一個連接
ESTABLISHED:正常數(shù)據(jù)傳輸狀態(tài)
FIN_WAIT1:應用說它已經(jīng)完成
FIN_WAIT2:另一邊已同意釋放
ITMED_WAIT:等待所有分組死掉
CLOSING:兩邊同時嘗試關(guān)閉
TIME_WAIT:另一邊已初始化一個釋放
LAST_ACK:等待所有分組死掉

進一步論述這個問題:
--------------客戶端主動關(guān)閉連接-----------------------

注意一個問題傍菇,進入TIME_WAIT狀態(tài)的一般情況下是客戶端。
大多數(shù)服務器端一般執(zhí)行被動關(guān)閉界赔,服務器不會進入TIME_WAIT狀態(tài)丢习。
當在服務器端關(guān)閉某個服務再重新啟動時,服務器是會進入TIME_WAIT狀態(tài)的淮悼。
舉例:
1.客戶端連接服務器的80服務咐低,這時客戶端會啟用一個本地的端口訪問服務器的80,訪問完成后關(guān)閉此連接袜腥,立刻再次訪問服務器的80渊鞋,這時客戶端會啟用另一個本地的端口,而不是剛才使用的那個本地端口瞧挤。原因就是剛才的那個連接還處于TIME_WAIT狀態(tài)锡宋。
2.客戶端連接服務器的80服務,這時服務器關(guān)閉80端口特恬,立即再次重啟80端口的服務执俩,這時可能不會成功啟動,原因也是服務器的連接還處于TIME_WAIT狀態(tài)癌刽。
服務端提供服務時役首,一般監(jiān)聽一個端口就夠了。例如Apache監(jiān)聽80端口显拜。
客戶端則是使用一個本地的空閑端口(大于1024)衡奥,與服務端的Apache的80端口建立連接。
當通信時使用短連接远荠,并由客戶端主動關(guān)閉連接時矮固,主動關(guān)閉連接的客戶端會產(chǎn)生TIME_WAIT狀態(tài)的連接,一個TIME_WAIT狀態(tài)的連接就占用了一個本地端口譬淳。這樣在TIME_WAIT狀態(tài)結(jié)束之前档址,本地最多就能承受6萬個TIME_WAIT狀態(tài)的連接,就無端口可用了邻梆。
客戶端與服務端進行短連接的TCP通信守伸,如果在同一臺機器上進行壓力測試模擬上萬的客戶請求,并且循環(huán)與服務端進行短連接通信浦妄,那么這臺機器將產(chǎn)生4000個左右的TIME_WAIT socket尼摹,后續(xù)的短連接就會產(chǎn)生address already in use : connect的異常见芹。

關(guān)閉的時候使用RST的方式,不進入 TIME_WAIT狀態(tài)蠢涝,是否可行玄呛?
--------------服務端主動關(guān)閉連接------------------------------
服務端提供在服務時,一般監(jiān)聽一個端口就夠了惠赫。例如Apache監(jiān)聽80端口把鉴。
客戶端則是使用一個本地的空閑端口(大于1024),與服務端的Apache的80端口建立連接儿咱。
當通信時使用短連接庭砍,并由服務端主動關(guān)閉連接時,主動關(guān)閉連接的服務端會產(chǎn)生TIME_WAIT狀態(tài)的連接混埠。
由于都連接到服務端80端口怠缸,服務端的TIME_WAIT狀態(tài)的連接會有很多個。
假如server一秒鐘處理1000個請求钳宪,那么就會積壓240秒*1000=24萬個TIME_WAIT的記錄揭北,服務有能力維護這24萬個記錄。

大多數(shù)服務器端一般執(zhí)行被動關(guān)閉吏颖,服務器不會進入TIME_WAIT狀態(tài)搔体。
服務端為了解決這個TIME_WAIT問題,可選擇的方式有三種:
? 保證由客戶端主動發(fā)起關(guān)閉(即做為B端)
? 關(guān)閉的時候使用RST的方式
? 對處于TIME_WAIT狀態(tài)的TCP允許重用

一般Apache的配置是:
Timeout 30  
KeepAlive On   #表示服務器端不會主動關(guān)閉鏈接  
MaxKeepAliveRequests 100  
KeepAliveTimeout 180  
表示:Apache不會主動關(guān)閉鏈接半醉,
兩種情況下Apache會主動關(guān)閉連接:
1疚俱、Apache收到了http協(xié)議頭中有客戶端要求Apache關(guān)閉連接信息,如setRequestHeader("Connection", "close");  
2缩多、連接保持時間達到了180秒的超時時間呆奕,將關(guān)閉。
如果配置如下:
KeepAlive Off   #表示服務器端會響應完數(shù)據(jù)后主動關(guān)閉鏈接  

--------------有代理時------------------------------
nginx代理使用了短鏈接的方式和后端交互衬吆,如果使用了nginx代理梁钾,那么系統(tǒng)TIME_WAIT的數(shù)量會變得比較多,這是由于nginx代理使用了短鏈接的方式和后端交互的原因逊抡,使得nginx和后端的ESTABLISHED變得很少而TIME_WAIT很多姆泻。這不但發(fā)生在安裝nginx的代理服務器上,而且也會使后端的app服務器上有大量的TIME_WAIT秦忿。查閱TIME_WAIT資料麦射,發(fā)現(xiàn)這個狀態(tài)很多也沒什么大問題,但可能因為它占用了系統(tǒng)過多的端口灯谣,導致后續(xù)的請求無法獲取端口而造成障礙。

對于大型的服務蛔琅,一臺server搞不定胎许,需要一個LB(Load Balancer)把流量分配到若干后端服務器上,如果這個LB是以NAT方式工作的話,可能會帶來問題辜窑。假如所有從LB到后端Server的IP包的source address都是一樣的(LB的對內(nèi)地址)钩述,那么LB到后端Server的TCP連接會受限制,因為頻繁的TCP連接建立和關(guān)閉穆碎,會在server上留下TIME_WAIT狀態(tài)牙勘,而且這些狀態(tài)對應的remote address都是LB的,LB的source port撐死也就60000多個(2^16=65536,1~1023是保留端口所禀,還有一些其他端口缺省也不會用)方面,每個LB上的端口一旦進入Server的TIME_WAIT黑名單,就有240秒不能再用來建立和Server的連接色徘,這樣LB和Server最多也就能支持300個左右的連接恭金。如果沒有LB,不會有這個問題褂策,因為這樣server看到的remote address是internet上廣闊無垠的集合横腿,對每個address,60000多個port實在是夠用了斤寂。

一開始我覺得用上LB會很大程度上限制TCP的連接數(shù)耿焊,但是實驗表明沒這回事,LB后面的一臺Windows Server 2003每秒處理請求數(shù)照樣達到了600個遍搞,難道TIME_WAIT狀態(tài)沒起作用罗侯?用Net Monitor和netstat觀察后發(fā)現(xiàn),Server和LB的XXXX端口之間的連接進入TIME_WAIT狀態(tài)后尾抑,再來一個LB的XXXX端口的SYN包歇父,Server照樣接收處理了,而是想像的那樣被drop掉了再愈。翻書榜苫,從書堆里面找出覆滿塵土的大學時代買的《UNIX Network Programming, Volume 1, Second Edition: Networking APIs: Sockets and XTI》,中間提到一句翎冲,對于BSD-derived實現(xiàn)垂睬,只要SYN的sequence number比上一次關(guān)閉時的最大sequence number還要大,那么TIME_WAIT狀態(tài)一樣接受這個SYN抗悍,難不成Windows也算BSD-derived?有了這點線索和關(guān)鍵字(BSD)驹饺,找到這個post,在NT4.0的時候缴渊,還是和BSD-derived不一樣的赏壹,不過Windows Server 2003已經(jīng)是NT5.2了,也許有點差別了衔沼。

做個試驗蝌借,用Socket API編一個Client端昔瞧,每次都Bind到本地一個端口比如2345,重復的建立TCP連接往一個Server發(fā)送Keep-Alive=false的HTTP請求菩佑,Windows的實現(xiàn)讓sequence number不斷的增長自晰,所以雖然Server對于Client的2345端口連接保持TIME_WAIT狀態(tài),但是總是能夠接受新的請求稍坯,不會拒絕酬荞。那如果SYN的Sequence Number變小會怎么樣呢?同樣用Socket API瞧哟,不過這次用Raw IP混巧,發(fā)送一個小sequence number的SYN包過去,Net Monitor里面看到绢涡,這個SYN被Server接收后如泥牛如海牲剃,一點反應沒有,被drop掉了雄可。

按照書上的說法凿傅,BSD-derived和Windows Server 2003的做法有安全隱患,不過至少這樣至少不會出現(xiàn)TIME_WAIT阻止TCP請求的問題数苫,當然聪舒,客戶端要配合,保證不同TCP連接的sequence number要上漲不要下降虐急。

Q: 我正在寫一個unix server程序箱残,不是daemon,經(jīng)常需要在命令行上重啟它止吁,絕大多數(shù)時候工作正常被辑,但是某些時候會報告"bind: address in use",于是重啟失敗敬惦。
A: Andrew Gierth
server程序總是應該在調(diào)用bind()之前設置SO_REUSEADDR套接字選項盼理。至于 TIME_WAIT狀態(tài),你無法避免俄删,那是TCP協(xié)議的一部分宏怔。

Q: 編寫 TCP/SOCK_STREAM 服務程序時,SO_REUSEADDR到底什么意思畴椰?
A: 這個套接字選項通知內(nèi)核臊诊,如果端口忙,但TCP狀態(tài)位于 TIME_WAIT 斜脂,可以重用 端口抓艳。如果端口忙,而TCP狀態(tài)位于其他狀態(tài)帚戳,重用端口時依舊得到一個錯誤信息壶硅, 指明"地址已經(jīng)使用中"威兜。如果你的服務程序停止后想立即重啟销斟,而新套接字依舊 使用同一端口庐椒,此時 SO_REUSEADDR 選項非常有用。必須意識到蚂踊,此時任何非期 望數(shù)據(jù)到達约谈,都可能導致服務程序反應混亂,不過這只是一種可能犁钟,事實上很不 可能棱诱。

一個套接字由相關(guān)五元組構(gòu)成,協(xié)議嗜价、本地地址履植、本地端口盼铁、遠程地址、遠程端 口靡菇。
SO_REUSEADDR 僅僅表示可以重用本地本地地址、本地端口米愿,整個相關(guān)五元組 還是唯一確定的厦凤。
所以,重啟后的服務程序有可能收到非期望數(shù)據(jù)育苟。必須慎重使用 SO_REUSEADDR 選項较鼓。
轉(zhuǎn)自:http://blog.sina.com.cn/s/blog_8e5d24890102w9yi.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市违柏,隨后出現(xiàn)的幾起案子博烂,更是在濱河造成了極大的恐慌,老刑警劉巖漱竖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禽篱,死亡現(xiàn)場離奇詭異,居然都是意外死亡闲孤,警方通過查閱死者的電腦和手機谆级,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讼积,“玉大人肥照,你說我怎么就攤上這事∏谥冢” “怎么了舆绎?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長们颜。 經(jīng)常有香客問我吕朵,道長猎醇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任努溃,我火速辦了婚禮硫嘶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梧税。我一直安慰自己沦疾,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布第队。 她就那樣靜靜地躺著哮塞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凳谦。 梳的紋絲不亂的頭發(fā)上忆畅,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音尸执,去河邊找鬼家凯。 笑死,一個胖子當著我的面吹牛剔交,可吹牛的內(nèi)容都是我干的肆饶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼岖常,長吁一口氣:“原來是場噩夢啊……” “哼驯镊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起竭鞍,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤板惑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后偎快,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冯乘,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年晒夹,在試婚紗的時候發(fā)現(xiàn)自己被綠了裆馒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡丐怯,死狀恐怖喷好,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情读跷,我是刑警寧澤梗搅,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響无切,放射性物質(zhì)發(fā)生泄漏荡短。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一哆键、第九天 我趴在偏房一處隱蔽的房頂上張望掘托。 院中可真熱鬧,春花似錦洼哎、人聲如沸烫映。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抽兆,卻和暖如春识补,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辫红。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工凭涂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贴妻。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓切油,卻偏偏與公主長得像,于是被迫代替她去往敵國和親名惩。 傳聞我的和親對象是個殘疾皇子澎胡,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355