SO_REUSEADDR
有過網(wǎng)絡(luò)編程經(jīng)驗(yàn)的人肯定都會(huì)遇到過關(guān)于 SO_REUSEADDR socket選項(xiàng)的問題。
問題背景:在socket編程中當(dāng)我們調(diào)用closesocket(或者close in linux)時(shí)會(huì)關(guān)閉兩端的連接,在TCP連接中主動(dòng)關(guān)閉的一方會(huì)進(jìn)入TIME_WAIT等待2MSL的時(shí)間之后才會(huì)真正關(guān)閉,這樣做是為了確保outdate的數(shù)據(jù)報(bào)被丟棄同時(shí)防止假連接的到來。那么這段時(shí)間該套接字所占用的端口并不會(huì)被釋放。
但是對(duì)于服務(wù)器這種存在大量連接,如果服務(wù)器需要重啟,在未設(shè)置SO_REUSEADDRSD時(shí),有時(shí)候會(huì)出現(xiàn)bind失敗的情況,原因就是因?yàn)榉?wù)器關(guān)閉的時(shí)候改端口會(huì)處在TIME_WAIT狀態(tài)2MSL長的時(shí)間段,短則幾十秒長則幾分鐘,這個(gè)對(duì)于服務(wù)器來說應(yīng)該是比較嚴(yán)重的問題。在Linux下可以通過在創(chuàng)建socket的時(shí)候bind之前對(duì)套接字設(shè)置SO_REUSEADDR選項(xiàng),這個(gè)選項(xiàng)在Linux系統(tǒng)上的作用是允許立即重用端口,那么就會(huì)在使處在TIME_WAIT狀態(tài)下的端口被立即重新使用。windows上也有這個(gè)socket選項(xiàng),然而在windows上的SO_REUSEADDR的含義確實(shí)大不一樣,windows設(shè)置這個(gè)選項(xiàng)的套接字可以共享同一端口,但是如果兩個(gè)監(jiān)聽套接字共享同一端口的話,如果有一個(gè)新的連接接入,那么帶來的行為將是未定義的。這種做法會(huì)帶來相應(yīng)的安全問題,我們可以通過監(jiān)聽同一端口來截獲某一服務(wù)的連接,這樣很容易竊取信息,微軟為了解決這個(gè)問題并沒有直接修改這個(gè)設(shè)置的作用,而是新增添了一個(gè)SO_EXLUSIVEADDRUSE選項(xiàng)配合使用,這個(gè)選項(xiàng)是指禁止兩個(gè)相同地址socket綁定到同一個(gè)socket上,即使設(shè)置SO_REUSEADDR選項(xiàng)。(MSDN解釋)
SO_LINGER
SO_LINGER選項(xiàng)控制著如何關(guān)閉TCP連接,在默認(rèn)情況下,當(dāng)調(diào)用close關(guān)閉socke的使用,close會(huì)立即返回,但是,如果send buffer中還有數(shù)據(jù),系統(tǒng)會(huì)試著先把send buffer中的數(shù)據(jù)發(fā)送出去,SO_LINGER選項(xiàng)則是用來修改這種默認(rèn)操作的。
struct linger {
int l_onoff //0=off, nonzero=on(開關(guān))
int l_linger //linger time(延遲時(shí)間)
}
其取值和處理如下:
1、設(shè)置 l_onoff為0,則該選項(xiàng)關(guān)閉,l_linger的值被忽略,等于內(nèi)核缺省情況,close調(diào)用會(huì)立即返回給調(diào)用者,如果可能將會(huì)傳輸任何未發(fā)送的數(shù)據(jù);
2、設(shè)置 l_onoff為非0,l_linger為0,當(dāng)調(diào)用close的時(shí)候,TCP連接會(huì)立即斷開.send buffer中未被發(fā)送的數(shù)據(jù)將被丟棄,并向?qū)Ψ桨l(fā)送一個(gè)RST信息.值得注意的是,由于這種方式,不是以4次握手方式結(jié)束TCP鏈接,所以,TCP連接將不會(huì)進(jìn)入TIME_WAIT狀態(tài),這樣會(huì)導(dǎo)致新建立的可能和就連接的數(shù)據(jù)造成混亂。這種關(guān)閉方式稱為“強(qiáng)制”或“失效”關(guān)閉。
3、設(shè)置 l_onoff 為非0,l_linger為非0,在這種情況下,回事的close返回得到延遲。調(diào)用close去關(guān)閉socket的時(shí)候,內(nèi)核將會(huì)延遲。也就是說,如果send buffer中還有數(shù)據(jù)尚未發(fā)送,該進(jìn)程將會(huì)被休眠直到一下任何一種情況發(fā)生:
a. send buffer中的所有數(shù)據(jù)都被發(fā)送并且得到對(duì)方TCP的應(yīng)答消息(這種應(yīng)答并不是意味著對(duì)方應(yīng)用程序已經(jīng)接收到數(shù)據(jù),在后面shutdown將會(huì)具體講道)
b.延遲時(shí)間消耗完。在延遲時(shí)間被消耗完之后,send buffer中的所有數(shù)據(jù)都將會(huì)被丟棄。
這種關(guān)閉稱為“優(yōu)雅的”關(guān)閉。