欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳談套接字中SO_REUSEPORT和SO_REUSEADDR的區(qū)別

 更新時(shí)間:2018年04月28日 15:07:44   作者:耀凱考前突擊大師  
下面小編就為大家分享一篇詳談套接字中SO_REUSEPORT和SO_REUSEADDR的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

Socket的基本背景

在討論這兩個(gè)選項(xiàng)的區(qū)別時(shí),我們需要知道的是BSD實(shí)現(xiàn)是所有socket實(shí)現(xiàn)的起源。基本上其他所有的系統(tǒng)某種程度上都參考了BSD socket實(shí)現(xiàn)(或者至少是其接口),然后開(kāi)始了它們自己的獨(dú)立發(fā)展進(jìn)化。顯然,BSD本身也是隨著時(shí)間在不斷發(fā)展變化的。所以較晚參考BSD的系統(tǒng)比較早參考BSD的系統(tǒng)多一些特性。所以理解BSD socket實(shí)現(xiàn)是理解其他socket實(shí)現(xiàn)的基石。下面我們就分析一下BSD socket實(shí)現(xiàn)。

在這之前,我們首先要明白如何唯一識(shí)別TCP/UDP連接。TCP/UDP是由以下五元組唯一地識(shí)別的:

{<protocol>, <src addr>, <src port>, <dest addr>, <dest port>}

這些數(shù)值組成的任何獨(dú)特的組合可以唯一地確一個(gè)連接。那么,對(duì)于任意連接,這五個(gè)值都不能完全相同。否則的話(huà)操作系統(tǒng)就無(wú)法區(qū)別這些連接了。

一個(gè)socket的協(xié)議是在用socket()初始化的時(shí)候就設(shè)置好的。源地址(source address)和源端口(source port)在調(diào)用bind()的時(shí)候設(shè)置。目的地址(destination address)和目的端口(destination port)在調(diào)用connect()的時(shí)候設(shè)置。其中UDP是無(wú)連接的,UDP socket可以在未與目的端口連接的情況下使用。但UDP也可以在某些情況下先與目的地址和端口建立連接后使用。在使用無(wú)連接UDP發(fā)送數(shù)據(jù)的情況下,如果沒(méi)有顯式地調(diào)用bind(),草錯(cuò)系統(tǒng)會(huì)在第一次發(fā)送數(shù)據(jù)時(shí)自動(dòng)將UDP socket與本機(jī)的地址和某個(gè)端口綁定(否則的話(huà)程序無(wú)法接受任何遠(yuǎn)程主機(jī)回復(fù)的數(shù)據(jù))。同樣的,一個(gè)沒(méi)有綁定地址的TCP socket也會(huì)在建立連接時(shí)被自動(dòng)綁定一個(gè)本機(jī)地址和端口。

如果我們手動(dòng)綁定一個(gè)端口,我們可以將socket綁定至端口0,綁定至端口0的意思是讓系統(tǒng)自己決定使用哪個(gè)端口(一般是從一組操作系統(tǒng)特定的提前決定的端口數(shù)范圍中),所以也就是任何端口的意思。同樣的,我們也可以使用一個(gè)通配符來(lái)讓系統(tǒng)決定綁定哪個(gè)源地址(ipv4通配符為0.0.0.0,ipv6通配符為::)。而與端口不同的是,一個(gè)socket可以被綁定到主機(jī)上所有接口所對(duì)應(yīng)的地址中的任意一個(gè)?;谶B接在本socket的目的地址和路由表中對(duì)應(yīng)的信息,操作系統(tǒng)將會(huì)選擇合適的地址來(lái)綁定這個(gè)socket,并用這個(gè)地址來(lái)取代之前的通配符IP地址。

在默認(rèn)情況下,任意兩個(gè)socket不能被綁定在同一個(gè)源地址和源端口組合上。比如說(shuō)我們將socketA綁定在A:X地址,將socketB綁定在B:Y地址,其中A和B是IP地址,X和Y是端口。那么在A==B的情況下X!=Y必須滿(mǎn)足,在X==Y的情況下A!=B必須滿(mǎn)足。需要注意的是,如果某一個(gè)socket被綁定在通配符IP地址下,那么事實(shí)上本機(jī)所有IP都會(huì)被系統(tǒng)認(rèn)為與其綁定了。例如一個(gè)socket綁定了0.0.0.0:21,在這種情況下,任何其他socket不論選擇哪一個(gè)具體的IP地址,其都不能再綁定在21端口下。因?yàn)橥ㄅ浞鸌P0.0.0.0與所有本地IP都沖突。

以上所有內(nèi)容基本上在主要操作系統(tǒng)中都相同。而各個(gè)中SO_REUSEADDR會(huì)有不同的含義。首先我們來(lái)討論BSD實(shí)現(xiàn)。因?yàn)锽SD試試其他所有socket實(shí)現(xiàn)方法的源頭。

BSD

SO_REUSEADDR

如果在一個(gè)socket綁定到某一地址和端口之前設(shè)置了其SO_REUSEADDR的屬性,那么除非本socket與產(chǎn)生了嘗試與另一個(gè)socket綁定到完全相同的源地址和源端口組合的沖突,否則的話(huà)這個(gè)socket就可以成功的綁定這個(gè)地址端口對(duì)。這聽(tīng)起來(lái)似乎和之前一樣。但是其中的關(guān)鍵字是完全。SO_REUSEADDR主要改變了系統(tǒng)對(duì)待通配符IP地址沖突的方式。

如果不用SO_REUSEADDR的話(huà),如果我們將socketA綁定到0.0.0.0:21,那么任何將本機(jī)其他socket綁定到端口21的舉動(dòng)(如綁定到192.168.1.1:21)都會(huì)導(dǎo)致EADDRINUSE錯(cuò)誤。因?yàn)?.0.0.0是一個(gè)通配符IP地址,意味著任意一個(gè)IP地址,所以任何其他本機(jī)上的IP地址都被系統(tǒng)認(rèn)為已被占用。如果設(shè)置了SO_REUSEADDR選項(xiàng),因?yàn)?.0.0.0:21和192.168.1.1:21并不是完全相同的地址端口對(duì)(其中一個(gè)是通配符IP地址,另一個(gè)是一個(gè)本機(jī)的具體IP地址),所以這樣的綁定是可以成功的。需要注意的是,無(wú)論socketA和socketB初始化的順序如何,只要設(shè)置了SO_REUSEADDR,綁定都會(huì)成功;而只要沒(méi)有設(shè)置SO_REUSEADDR,綁定都不會(huì)成功。

下面的表格列出了一些可能的情況及其結(jié)果。

SO_REUSEADDR socketA socketB Result
ON / OFF 192.168.1.1:21 192.168.1.1:21 ERROR(EADDRINUSE)
ON / OFF 192.168.1.1:21 10.0.1.1:21 OK
ON / OFF 10.0.1.1:21 192.168.1.1:21 OK
OFF 192.168.1.1:21 0.0.0.0:21 ERROR(EADDRINUSE)
OFF 0.0.0.0:21 192.168.1.1:21 ERROR(EADDRINUSE)
ON 192.168.1.1:21 0.0.0.0:21 OK
ON 0.0.0.0:21 192.168.1.1:21 OK
ON / OFF 0.0.0.0:21 0.0.0.0:21 OK

這個(gè)表格假定socketA已經(jīng)成功地綁定了表格中對(duì)應(yīng)的地址,然后socketB被初始化了,其SO_REUSEADDR設(shè)置的情況如表格第一列所示,然后socketB試圖綁定表格中對(duì)應(yīng)地址。Result列是其綁定的結(jié)果。如果第一列中的值是ON/OFF,那么SO_REUSEADDR設(shè)置與否都與結(jié)果無(wú)關(guān)。

上面討論了SO_REUSEADDR對(duì)通配符IP地址的作用,但其并不只有這一作用。其另一作用也是為什么大家在進(jìn)行服務(wù)器端編程的時(shí)候會(huì)采用SO_REUSEADDR選項(xiàng)的原因。為了理解其另一個(gè)作用及其重要應(yīng)用,我們需要先更深入地討論一下TCP協(xié)議的工作原理。

每一個(gè)socket都有其相應(yīng)的發(fā)送緩沖區(qū)(buffer)。當(dāng)成功調(diào)用其send()方法的時(shí)候,實(shí)際上我們所要求發(fā)送的數(shù)據(jù)并不一定被立即發(fā)送出去,而是被添加到了發(fā)送緩沖區(qū)中。對(duì)于UDP socket來(lái)說(shuō),即使不是馬上被發(fā)送,這些數(shù)據(jù)一般也會(huì)被很快發(fā)送出去。但對(duì)于TCP socket來(lái)說(shuō),在將數(shù)據(jù)添加到發(fā)送緩沖區(qū)之后,可能需要等待相對(duì)較長(zhǎng)的時(shí)間之后數(shù)據(jù)才會(huì)被真正發(fā)送出去。因此,當(dāng)我們關(guān)閉了一個(gè)TCP socket之后,其發(fā)送緩沖區(qū)中可能實(shí)際上還仍然有等待發(fā)送的數(shù)據(jù)。但此時(shí)因?yàn)閟end()返回了成功,我們的代碼認(rèn)為數(shù)據(jù)已經(jīng)實(shí)際上被成功發(fā)送了。如果TCP socket在我們調(diào)用close()之后直接關(guān)閉,那么所有這些數(shù)據(jù)都將會(huì)丟失,而我們的代碼根本不會(huì)知道。但是,TCP是一個(gè)可靠的傳輸層協(xié)議,直接丟棄這些待傳輸?shù)臄?shù)據(jù)顯然是不可取的。實(shí)際上,如果在socket的發(fā)送緩沖區(qū)中還有待發(fā)送數(shù)據(jù)的情況下調(diào)用了其close()方法,其將會(huì)進(jìn)入一個(gè)所謂的TIME_WAIT狀態(tài)。在這個(gè)狀態(tài)下,socket將會(huì)持續(xù)嘗試發(fā)送緩沖區(qū)的數(shù)據(jù)直到所有數(shù)據(jù)都被成功發(fā)送或者直到超時(shí),超時(shí)被觸發(fā)的情況下socket將會(huì)被強(qiáng)制關(guān)閉。

操作系統(tǒng)的kernel在強(qiáng)制關(guān)閉一個(gè)socket之前的最長(zhǎng)等待時(shí)間被稱(chēng)為延遲時(shí)間(Linger Time)。在大部分系統(tǒng)中延遲時(shí)間都已經(jīng)被全局設(shè)置好了,并且相對(duì)較長(zhǎng)(大部分系統(tǒng)將其設(shè)置為2分鐘)。我們也可以在初始化一個(gè)socket的時(shí)候使用SO_LINGER選項(xiàng)來(lái)特定地設(shè)置每一個(gè)socket的延遲時(shí)間。我們甚至可以完全關(guān)閉延遲等待。但是需要注意的是,將延遲時(shí)間設(shè)置為0(完全關(guān)閉延遲等待)并不是一個(gè)好的編程實(shí)踐。因?yàn)閮?yōu)雅地關(guān)閉TCP socket是一個(gè)比較復(fù)雜的過(guò)程,過(guò)程中包括與遠(yuǎn)程主機(jī)交換數(shù)個(gè)數(shù)據(jù)包(包括在丟包的情況下的丟失重傳),而這個(gè)數(shù)據(jù)包交換的過(guò)程所需要的時(shí)間也包括在延遲時(shí)間中。如果我們停用延遲等待,socket不止會(huì)在關(guān)閉的時(shí)候直接丟棄所有待發(fā)送的數(shù)據(jù),而且總是會(huì)被強(qiáng)制關(guān)閉(由于TCP是面向連接的協(xié)議,不與遠(yuǎn)端端口交換關(guān)閉數(shù)據(jù)包將會(huì)導(dǎo)致遠(yuǎn)端端口處于長(zhǎng)時(shí)間的等待狀態(tài))。所以通常我們并不推薦在實(shí)際編程中這樣做。TCP斷開(kāi)連接的過(guò)程超出了本文討論的范圍,如果對(duì)此有興趣,可以參考這個(gè)頁(yè)面。并且實(shí)際上,如果我們禁用了延遲等待,而我們的程序沒(méi)有顯式地關(guān)閉socket就退出了,BSD(可能包括其他系統(tǒng))會(huì)忽略我們的設(shè)置進(jìn)行延遲等待。例如,如果我們的程序調(diào)用了exit()方法,或者其進(jìn)程被使用某個(gè)信號(hào)終止了(包括進(jìn)程因?yàn)榉欠▋?nèi)存訪問(wèn)之類(lèi)的情況而崩潰)。所以我們無(wú)法百分之百保證一個(gè)socket在所有情況下忽略延遲等待時(shí)間而終止。

這里的問(wèn)題在于操作系統(tǒng)如何對(duì)待處于TIME_WAIT階段的socket。如果SO_REUSEADDR選項(xiàng)沒(méi)有被設(shè)置,處于TIME_WAIT階段的socket任然被認(rèn)為是綁定在原來(lái)那個(gè)地址和端口上的。直到該socket被完全關(guān)閉之前(結(jié)束TIME_WAIT階段),任何其他企圖將一個(gè)新socket綁定該該地址端口對(duì)的操作都無(wú)法成功。這一等待的過(guò)程可能和延遲等待的時(shí)間一樣長(zhǎng)。所以我們并不能馬上將一個(gè)新的socket綁定到一個(gè)剛剛被關(guān)閉的socket對(duì)應(yīng)的地址端口對(duì)上。在大多數(shù)情況下這種操作都會(huì)失敗。

然而,如果我們?cè)谛碌膕ocket上設(shè)置了SO_REUSEADDR選項(xiàng),如果此時(shí)有另一個(gè)socket綁定在當(dāng)前的地址端口對(duì)且處于TIME_WAIT階段,那么這個(gè)已存在的綁定關(guān)系將會(huì)被忽略。事實(shí)上處于TIME_WAIT階段的socket已經(jīng)是半關(guān)閉的狀態(tài),將一個(gè)新的socket綁定在這個(gè)地址端口對(duì)上不會(huì)有任何問(wèn)題。這樣的話(huà)原來(lái)綁定在這個(gè)端口上的socket一般不會(huì)對(duì)新的socket產(chǎn)生影響。但需要注意的是,在某些時(shí)候,將一個(gè)新的socket綁定在一個(gè)處于TIME_WAIT階段但仍在工作的socket所對(duì)應(yīng)的地址端口對(duì)會(huì)產(chǎn)生一些我們并不想要的,無(wú)法預(yù)料的負(fù)面影響。但這個(gè)問(wèn)題超過(guò)了本文的討論范圍。而且幸運(yùn)的是這些負(fù)面影響在實(shí)踐中很少見(jiàn)到。

最后,關(guān)于SO_REUSEADDR,我們還要注意的一件事是,以上所有內(nèi)容只要我們對(duì)新的socket設(shè)置了SO_REUSEADDR就成立。至于原有的已經(jīng)綁定在當(dāng)前地址端口對(duì)上的,處于或不處于TIME_WAIT階段的socket是否設(shè)置了SO_REUSEADDR并無(wú)影響。決定bind操作是否成功的代碼僅僅會(huì)檢查新的被傳遞到bind()方法的socket的SO_REUSEADDR選項(xiàng)。其他涉及到的socket的SO_REUSEADDR選項(xiàng)并不會(huì)被檢查。

SO_REUSEPORT

許多人將SO_REUSEADDR當(dāng)成了SO_REUSEPORT?;旧蟻?lái)說(shuō),SO_REUSEPORT允許我們將任意數(shù)目的socket綁定到完全相同的源地址端口對(duì)上,只要所有之前綁定的socket都設(shè)置了SO_REUSEPORT選項(xiàng)。如果第一個(gè)綁定在該地址端口對(duì)上的socket沒(méi)有設(shè)置SO_REUSEPORT,無(wú)論之后的socket是否設(shè)置SO_REUSEPORT,其都無(wú)法綁定在與這個(gè)地址端口完全相同的地址上。除非第一個(gè)綁定在這個(gè)地址端口對(duì)上的socket釋放了這個(gè)綁定關(guān)系。與SO_REUSEADDR不同的是 ,處理SO_REUSEPORT的代碼不僅會(huì)檢查當(dāng)前嘗試綁定的socket的SO_REUSEPORT,而且也會(huì)檢查之前已綁定了當(dāng)前嘗試綁定的地址端口對(duì)的socket的SO_REUSEPORT選項(xiàng)。

SO_REUSEPORT并不等于SO_REUSEADDR。這么說(shuō)的含義是如果一個(gè)已經(jīng)綁定了地址的socket沒(méi)有設(shè)置SO_REUSEPORT,而另一個(gè)新socket設(shè)置了SO_REUSEPORT且嘗試綁定到與當(dāng)前socket完全相同的端口地址對(duì),這次綁定嘗試將會(huì)失敗。同時(shí),如果當(dāng)前socket已經(jīng)處于TIME_WAIT階段,而這個(gè)設(shè)置了SO_REUSEPORT選項(xiàng)的新socket嘗試綁定到當(dāng)前地址,這個(gè)綁定操作也會(huì)失敗。為了能夠?qū)⑿碌膕ocket綁定到一個(gè)當(dāng)前處于TIME_WAIT階段的socket對(duì)應(yīng)的地址端口對(duì)上,我們要么需要在綁定之前設(shè)置這個(gè)新socket的SO_REUSEADDR選項(xiàng),要么需要在綁定之前給兩個(gè)socket都設(shè)置SO_REUSEPORT選項(xiàng)。當(dāng)然,同時(shí)給socket設(shè)置SO_REUSEADDR和SO_REUSEPORT選項(xiàng)是也是可以的。

SO_REUSEPORT是在SO_REUSEADDR之后被添加到BSD系統(tǒng)中的。這也是為什么現(xiàn)在有些系統(tǒng)的socket實(shí)現(xiàn)里沒(méi)有SO_REUSEPORT選項(xiàng)。因?yàn)樗鼈冊(cè)谶@個(gè)選項(xiàng)被加入BSD系統(tǒng)之前參考了BSD的socket實(shí)現(xiàn)。而在這個(gè)選項(xiàng)被加入之前,BSD系統(tǒng)下沒(méi)有任何辦法能夠?qū)蓚€(gè)socket綁定在完全相同的地址端口對(duì)上。

Connect()返回EADDRINUSE?

有些時(shí)候bind()操作會(huì)返回EADDRINUSE錯(cuò)誤。但奇怪的是,在我們調(diào)用connect()操作時(shí),也有可能得到EADDRINUSE錯(cuò)誤。這是為什么呢?為何一個(gè)我們嘗試令當(dāng)前端口建立連接的遠(yuǎn)程地址也會(huì)被占用呢?難道將多個(gè)socket連接到同一個(gè)遠(yuǎn)程地址的操作會(huì)有什么問(wèn)題產(chǎn)生嗎?

正如本文之前所說(shuō),一個(gè)連接關(guān)系是由一個(gè)五元組確定的。對(duì)于任意的連接關(guān)系而言,這個(gè)五元組必須是唯一的。否則的話(huà),系統(tǒng)將無(wú)法分辨兩個(gè)連接。而現(xiàn)在當(dāng)我們采用了地址復(fù)用之后,我們可以將兩個(gè)采用相同協(xié)議的socket綁定到同一地址端口對(duì)上。這意味著對(duì)這兩個(gè)socket而言,五元組里的{<protocol>, <src addr>, <src port>}已經(jīng)相同了。在這種情況下,如果我們嘗試將它們都連接到同一個(gè)遠(yuǎn)程地址端口上,這兩個(gè)連接關(guān)系的五元組將完全相同。也就是說(shuō),產(chǎn)生了兩個(gè)完全相同的連接。在TCP協(xié)議中這是不被允許的(UDP是無(wú)連接的)。如果這兩個(gè)完全相同的連接種的某一個(gè)接收到了數(shù)據(jù),系統(tǒng)將無(wú)法分辨這個(gè)數(shù)據(jù)到底屬于哪個(gè)連接。所以在這種情況下,至少這兩個(gè)socket所嘗試連接的遠(yuǎn)程主機(jī)的地址和端口不能相同。只有如此,系統(tǒng)才能繼續(xù)區(qū)分這兩個(gè)連接關(guān)系。

所以當(dāng)我們將兩個(gè)采用相同協(xié)議的socket綁定到同一個(gè)本地地址端口對(duì)上后,如果我們還嘗試讓它們和同一個(gè)目的地址端口對(duì)建立連接,第二個(gè)嘗試調(diào)用connect()方法的socket將會(huì)報(bào)EADDRINUSE的錯(cuò)誤,這說(shuō)明一個(gè)擁有完全相同的五元組的socket已經(jīng)存在了。

Multicast Address

相對(duì)于用于一對(duì)一通信的unicast地址,multicast地址用于一對(duì)多通信。IPv4和IPv6都擁有multicast地址。但是IPv4中的multicast實(shí)際上在公共網(wǎng)路上很少被使用。

SO_REUSEADDR的意義在multicast地址的情況下會(huì)與之前有所不同。在這種情況下,SO_REUSEADDR允許我們將多個(gè)socket綁定至完全相同的源廣播地址端口對(duì)上。換句話(huà)說(shuō),對(duì)于multicast地址而言,SO_REUSEADDR的作用相當(dāng)于unicast通信中的SO_REUSEPORT。事實(shí)上,在multicast情況下,SO_REUSEADDR和SO_REUSEPORT的作用完全相同。

FreeBSD/OpenBSD/NetBSD

所有這些系統(tǒng)都是參考了較新的原生BSD系統(tǒng)代碼。所以這三個(gè)系統(tǒng)提供與BSD完全相同的socket選項(xiàng),這些選項(xiàng)的含義與原生BSD完全相同。

MacOS X

MacOS X的核心代碼實(shí)現(xiàn)是基于較新版本的原生BSD的BSD風(fēng)格的UNIX,所以MacOS X提供與BSD完全相同的socket選項(xiàng),并且它們的含義也與BSD系統(tǒng)相同。

iOS

iOS事實(shí)上是一個(gè)略微改造過(guò)的MacOS X,所以適用于MacOS X的也適用于iOS。

Linux

在Linux3.9之前,只有SO_REUSEADDR選項(xiàng)存在。這個(gè)選項(xiàng)的作用基本上同BSD系統(tǒng)下相同。但其仍有兩個(gè)重要的區(qū)別。

第一個(gè)區(qū)別是如果一個(gè)處于監(jiān)聽(tīng)(服務(wù)器)狀態(tài)下的TCP socket已經(jīng)被綁定到了一個(gè)通配符IP地址和一個(gè)特定端口下,那么不論這兩個(gè)socket有沒(méi)有設(shè)置SO_REUSEADDR選項(xiàng),任何其他TCP socket都無(wú)法再被綁定到相同的端口下。即使另一個(gè)socket使用了一個(gè)具體IP地址(像在BSD系統(tǒng)中允許的那樣)也不行。而非監(jiān)聽(tīng)(客戶(hù))TCP socket則無(wú)此限制。

第二個(gè)區(qū)別是對(duì)于UDP socket來(lái)說(shuō),SO_REUSEADDR的作用和BSD中SO_REUSEPORT完全相同。所以?xún)蓚€(gè)UDP socket如果都設(shè)置了SO_REUSEADDR的話(huà),它們就可以被綁定在一組完全相同的地址端口對(duì)上。

Linux3.9加入了SO_REUSEPORT選項(xiàng)。只要所有socket(包括第一個(gè))在綁定地址前設(shè)置了這個(gè)選項(xiàng),兩個(gè)或多個(gè),TCP或UDP,監(jiān)聽(tīng)(服務(wù)器)或非監(jiān)聽(tīng)(客戶(hù))socket就可以被綁定在完全相同的地址端口組合下。同時(shí),為了防止端口劫持(port hijacking),還有一個(gè)特別的限制:所有試圖綁定在相同的地址端口組合的socket必須屬于擁有相同用戶(hù)ID的進(jìn)程。所以一個(gè)用戶(hù)無(wú)法從另一個(gè)用戶(hù)那里“偷竊”端口。

除此之外,對(duì)于設(shè)置了SO_REUSEPORT選項(xiàng)的socket,Linux kernel還會(huì)執(zhí)行一些別的系統(tǒng)所沒(méi)有的特別的操作:對(duì)于綁定于同一地址端口組合上的UDP socket,kernel嘗試在它們之間平均分配收到的數(shù)據(jù)包;對(duì)于綁定于同一地址端口組合上的TCP監(jiān)聽(tīng)socket,kernel嘗試在它們之間平均分配收到的連接請(qǐng)求(調(diào)用accept()方法所得到的請(qǐng)求)。這意味著相比于其他允許地址復(fù)用但隨機(jī)將收到的數(shù)據(jù)包或者連接請(qǐng)求分配給連接在同一地址端口組合上的socket的系統(tǒng)而言,Linux嘗試了進(jìn)行流量分配上的優(yōu)化。比如一個(gè)簡(jiǎn)單的服務(wù)器進(jìn)程的幾個(gè)不同實(shí)例可以方便地使用SO_REUSEPORT來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的負(fù)載均衡,而且這個(gè)負(fù)載均衡有kernel負(fù)責(zé), 對(duì)程序來(lái)說(shuō)完全免費(fèi)!

Android

Android的核心部分是略微修改過(guò)的Linux kernel,所以所有適用于Linux的操作也適用于Android。

Windows

Windows僅有SO_REUSEADDR選項(xiàng)。在Windows中對(duì)一個(gè)socket設(shè)置SO_REUSEADDR的效果與在BSD下同時(shí)對(duì)一個(gè)socket設(shè)置SO_REUSEPORT和SO_REUSEADDR相同。但其區(qū)別在于:即使另一個(gè)已綁定地址的socket并沒(méi)有設(shè)置SO_REUSEADDR,一個(gè)設(shè)置了SO_REUSEADDR的socket總是可以綁定到與另一個(gè)已綁定的socket完全相同的地址端口組合上。這個(gè)行為可以說(shuō)是有些危險(xiǎn)的。因?yàn)樗试S了一個(gè)應(yīng)用從另一個(gè)引用已連接的端口上偷取數(shù)據(jù)。微軟意識(shí)到了這個(gè)問(wèn)題,因此添加了另一個(gè)socket選項(xiàng):SO_EXCLUSIVEADDRUSE。對(duì)一個(gè)socket設(shè)置SO_EXCLUSIVEADDRUSE可以確保一旦該socket綁定了一個(gè)地址端口組合,任何其他socket,不論設(shè)置SO_REUSEADDR與否,都無(wú)法再綁定當(dāng)前的地址端口組合。

Solaris

Solaris是SunOS的繼任者。SunOS從某種程度上來(lái)說(shuō)也是一個(gè)較早版本的BSD的一個(gè)支路。因此Solaris只提供SO_REUSEADDR,且其表現(xiàn)和BSD系統(tǒng)中基本相同。據(jù)我所知,在Solaris系統(tǒng)中無(wú)法實(shí)現(xiàn)與SO_REUSEPORT相同的功能。這意味著在Solaris中無(wú)法將兩個(gè)socket綁定到完全相同的地址端口組合下。

與Windows類(lèi)似的是,Solaris也為socket提供獨(dú)占綁定的選項(xiàng)——SO_EXCLBIND。如果一個(gè)socket在綁定地址前設(shè)置了這個(gè)選項(xiàng),即使其他socket設(shè)置了SO_REUSEADDR也將無(wú)法綁定至相同地址。例如:如果socketA綁定在了通配符IP地址下,而socketB設(shè)置了SO_REUSEADDR且綁定在一個(gè)具體IP地址和與socketA相同的端口的組合下,這個(gè)操作在socketA沒(méi)有設(shè)置SO_EXCLBIND的情況下會(huì)成功,否則會(huì)失敗。

Reference:

http://stackoverflow.com/a/14388707/6037083

以上這篇詳談套接字中SO_REUSEPORT和SO_REUSEADDR的區(qū)別就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python 第一步 hello world

    Python 第一步 hello world

    Python 第一步 hello world 入門(mén)學(xué)習(xí)。
    2009-09-09
  • Python算法應(yīng)用實(shí)戰(zhàn)之棧詳解

    Python算法應(yīng)用實(shí)戰(zhàn)之棧詳解

    棧是什么,你可以理解為一種先入后出的數(shù)據(jù)結(jié)構(gòu)(First In Last Out),一種操作受限的線(xiàn)性表。下面這篇文章主要給大家介紹了Python中棧的應(yīng)用實(shí)戰(zhàn),文中給出了多個(gè)實(shí)例,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-02-02
  • 在VScode里面添加Python解釋器的詳細(xì)步驟

    在VScode里面添加Python解釋器的詳細(xì)步驟

    VScode編輯器在安裝好Python插件之后會(huì)自動(dòng)選擇環(huán)境變量中排序最高的那一個(gè)解釋器作為默認(rèn)解釋器,而想要額外添加新的Python解釋器就需要自己設(shè)置,接下來(lái)通過(guò)本文給大家分享VScode添加Python解釋器的方法,感興趣的朋友一起看看吧
    2023-02-02
  • Python類(lèi)的多重繼承問(wèn)題深入分析

    Python類(lèi)的多重繼承問(wèn)題深入分析

    昨天在Python類(lèi)的多重繼承那里糾結(jié)了好久,咨詢(xún)了不少高手之后,才完全搞明白,現(xiàn)在把類(lèi)的特性整理下,供以后參考,也給有需要的小伙伴們參考下
    2014-11-11
  • 通過(guò)python爬蟲(chóng)mechanize庫(kù)爬取本機(jī)ip地址的方法

    通過(guò)python爬蟲(chóng)mechanize庫(kù)爬取本機(jī)ip地址的方法

    python中的mechanize算是一個(gè)比較古老的庫(kù)了,在python2的時(shí)代中,使用的多一些,在python3以后就很少使用了,現(xiàn)在已經(jīng)是2202年了,可能很多人都沒(méi)聽(tīng)說(shuō)過(guò)mechanize,這不要緊,我們先來(lái)簡(jiǎn)單的講解一下,如何使用mechanize,感興趣的朋友一起看看吧
    2022-08-08
  • python數(shù)據(jù)可視化之條形圖畫(huà)法

    python數(shù)據(jù)可視化之條形圖畫(huà)法

    這篇文章主要為大家詳細(xì)介紹了python數(shù)據(jù)可視化之條形圖畫(huà)法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Python腳本實(shí)現(xiàn)自動(dòng)登錄校園網(wǎng)

    Python腳本實(shí)現(xiàn)自動(dòng)登錄校園網(wǎng)

    今天給大家?guī)?lái)的是關(guān)于Python的相關(guān)知識(shí),文章圍繞著如何使用Python腳本實(shí)現(xiàn)自動(dòng)登錄校園網(wǎng)展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Python學(xué)習(xí)教程之常用的內(nèi)置函數(shù)大全

    Python學(xué)習(xí)教程之常用的內(nèi)置函數(shù)大全

    python給我們提供了很多已經(jīng)定義好的函數(shù),下面這篇文章主要給大家介紹了關(guān)于Python學(xué)習(xí)教程之一些常用的內(nèi)置函數(shù),文中分享了關(guān)于數(shù)學(xué)函數(shù)、功能函數(shù)、類(lèi)型轉(zhuǎn)換函數(shù)、字符串處理和序列處理函數(shù)的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-07-07
  • python實(shí)現(xiàn)四舍五入方式

    python實(shí)現(xiàn)四舍五入方式

    這篇文章主要介紹了python實(shí)現(xiàn)四舍五入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Python?pydash庫(kù)處理大規(guī)模數(shù)據(jù)集執(zhí)行復(fù)雜操作

    Python?pydash庫(kù)處理大規(guī)模數(shù)據(jù)集執(zhí)行復(fù)雜操作

    在數(shù)據(jù)處理和分析領(lǐng)域,Python一直是一種強(qiáng)大的編程語(yǔ)言,然而,在處理大規(guī)模數(shù)據(jù)集和執(zhí)行復(fù)雜操作時(shí),有時(shí)候需要更高效的工具,在本文中,我們將深入探討pydash庫(kù),這是一個(gè)專(zhuān)注于提高Python代碼性能的工具
    2023-12-12

最新評(píng)論