剛剛開始使用flask框架寫了兩個小程序。然后我先訪問了第一個“Hello,Web”的小程序,運行通過,然后想看看第二個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連接時全雙工的,因此,每個方向都必須要單獨進(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