剛剛開始使用flask框架寫了兩個小程序烹骨。然后我先訪問了第一個“Hello糟袁,Web”的小程序弊予,運(yùn)行通過,然后想看看第二個inputname的程序是不是寫對吹菱,但是linux報錯:
socket.error: [Errno 98] Address already in use
大概意思就是地址被占用猛铅。因為socket默認(rèn)是不支持地址復(fù)用的火架。為什么程序跑完了端口還是被占用著馆匿?這個問題就要TCP連接的“四次揮手”。
我們可能都有聽過TCP/IP中“三次握手梨撞,四次揮手”雹洗,前者我們可能會更加了解一點,后者就不知道是什么樣子卧波。我也是T_T,所以我決定弄懂它时肿。
三次握手
(1)第一次握手:Client將標(biāo)志位SYN置為1,隨機(jī)產(chǎn)生一個值seq=J港粱,并將該數(shù)據(jù)包發(fā)送給Server螃成,Client進(jìn)入SYN_SENT狀態(tài),等待Server確認(rèn)查坪。
(2)第二次握手:Server收到數(shù)據(jù)包后由標(biāo)志位SYN=1知道Client請求建立連接寸宏,Server將標(biāo)志位SYN和ACK都置為1,ack=J+1偿曙,隨機(jī)產(chǎn)生一個值seq=K氮凝,并將該數(shù)據(jù)包發(fā)送給Client以確認(rèn)連接請求,Server進(jìn)入SYN_RCVD狀態(tài)望忆。
(3)第三次握手:Client收到確認(rèn)后罩阵,檢查ack是否為J+1,ACK是否為1启摄,如果正確則將標(biāo)志位ACK置為1稿壁,ack=K+1,并將該數(shù)據(jù)包發(fā)送給Server歉备,Server檢查ack是否為K+1傅是,ACK是否為1,如果正確則連接建立成功,Client和Server進(jìn)入ESTABLISHED狀態(tài)落午,完成三次握手谎懦,隨后Client與Server之間可以開始傳輸數(shù)據(jù)了肚豺。
四次揮手
由于TCP連接時全雙工的溃斋,因此,每個方向都必須要單獨(dú)進(jìn)行關(guān)閉吸申,這一原則是當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后梗劫,發(fā)送一個FIN來終止這一方向的連接,收到一個FIN只是意味著這一方向上沒有數(shù)據(jù)流動了截碴,即不會再收到數(shù)據(jù)了梳侨,但是在這個TCP連接上仍然能夠發(fā)送數(shù)據(jù),直到這一方向也發(fā)送了FIN日丹。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動關(guān)閉走哺,而另一方則執(zhí)行被動關(guān)閉,上圖描述的即是如此哲虾。
(1)第一次揮手:Client發(fā)送一個FIN丙躏,用來關(guān)閉Client到Server的數(shù)據(jù)傳送,Client進(jìn)入FIN_WAIT_1狀態(tài)束凑。
(2)第二次揮手:Server收到FIN后晒旅,發(fā)送一個ACK給Client,確認(rèn)序號為收到序號+1(與SYN相同汪诉,一個FIN占用一個序號)废恋,Server進(jìn)入CLOSE_WAIT狀態(tài)。
(3)第三次揮手:Server發(fā)送一個FIN扒寄,用來關(guān)閉Server到Client的數(shù)據(jù)傳送鱼鼓,Server進(jìn)入LAST_ACK狀態(tài)。
(4)第四次揮手:Client收到FIN后该编,Client進(jìn)入TIME_WAIT狀態(tài)迄本,接著發(fā)送一個ACK給Server,確認(rèn)序號為收到序號+1上渴,Server進(jìn)入CLOSED狀態(tài)岸梨,完成四次揮手。
在TCP/IP終止連接的四次握手中稠氮,當(dāng)最后的ACK回復(fù)發(fā)出后曹阔,有個2MSL的時間等待,MSL指一個片段在網(wǎng)絡(luò)中最大的存活時間隔披,這個時間一般是30秒赃份,所以基本上過60秒后就可以重新連接!
為什么要等待2MSL?是因為在最后發(fā)出ACK回復(fù)后抓韩,發(fā)送方不能確認(rèn)ACK是否被另一端正常收到纠永,如果另一端沒有收到ACK回復(fù)的話,將會在1MSL后再次發(fā)送FIN片段谒拴。所以說發(fā)送方等待2MSL時間尝江,也就是剛好它發(fā)ACK回復(fù)和對方發(fā)送FIN片段的時間,如果此時間內(nèi)都沒有再次收到FIN片段的話英上,發(fā)送方就假設(shè)對方已經(jīng)正常接收到了ACK回復(fù)炭序,此時它就會正常關(guān)閉連接!
以上就解釋了為什么會出現(xiàn)跑另一個程序時會出現(xiàn)地址占用的情況苍日。
接下去就是解決方案:
如果并發(fā)連接請求過多的時候惭聂,即短時間內(nèi)連接請求很多,系統(tǒng)自動釋放已占用端口的時間還沒有到相恃,又有連接請求(可用的端口已經(jīng)被用完)辜纲,所以還會出現(xiàn) Address already in use錯誤提示),就會產(chǎn)生大量的TIME_WAIT狀態(tài)的連接拦耐。這種情況下就有必要調(diào)整下linux的TCP/IP內(nèi)核參數(shù)耕腾,讓系統(tǒng)更快的釋放TIME_WAIT連接。對于并發(fā)連接量大的情況我們需要這樣設(shè)置:
用vi打開配置文件:
# vi /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 = 5
最后輸入下面的命令,讓內(nèi)核參數(shù)生效:
# /sbin/sysctl -p