日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

SO_REUSEADDR SO_REUSEPORT 解析

發(fā)布時(shí)間:2025/3/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SO_REUSEADDR SO_REUSEPORT 解析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先我們需要了解一些基本知識(shí),一個(gè)TCP/UDP連接是被一個(gè)五元組確定的{源地址,源端口,協(xié)議,目的端口,目的地址}。

因此,任何兩個(gè)連接都不可能擁有相同的五元組,否則系統(tǒng)將無(wú)法區(qū)別這兩個(gè)連接。

當(dāng)使用socket()函數(shù)創(chuàng)建套接字的時(shí)候,我們就指定了該套接字使用的protocol(協(xié)議),bind()函數(shù)設(shè)置了源地址和源端口號(hào),而目的地址和目的端口號(hào)則由connect()函數(shù)設(shè)定。

盡管允許對(duì)UDP進(jìn)行"連接",但由于UDP是一個(gè)無(wú)連接協(xié)議,UDP套接字仍然可以不經(jīng)連接就使用。"未連接"的UDP套接字在數(shù)據(jù)被第一次發(fā)送之前并不會(huì)綁定,只有在發(fā)送的時(shí)候被系統(tǒng)自動(dòng)綁定,因此未綁定的UDP套接字也就無(wú)法收到(回復(fù))數(shù)據(jù)。未綁定的TCP也一樣,它將在連接的時(shí)候自動(dòng)綁定。

如果你明確綁定一個(gè)socket,把它綁定到端口0是可行的,它意味著"any port"("任意端口")。由于一個(gè)套接字無(wú)法真正的被綁定到系統(tǒng)上的所有端口,那么在這種情況下系統(tǒng)將不得不選擇一個(gè)具體的端口號(hào)。源地址使用類(lèi)似的通配符,也就是"0.0.0.0" 。和端口不同的是,一個(gè)套接字可以被綁定到任意地址,這里指本地網(wǎng)絡(luò)接口的所有地址由于socket無(wú)法在連接的時(shí)候同時(shí)綁定到所有源IP地址,因此當(dāng)接下來(lái)有一個(gè)連接過(guò)來(lái)的時(shí)候,系統(tǒng)將不得不挑選一個(gè)源IP地址。考慮到目的地址和路由表中的路由信息,系統(tǒng)將會(huì)選擇一個(gè)合適的源地址,并將任意地址替換為一個(gè)選定的地址作為源地址。

默認(rèn)情況下,任意兩個(gè)socket都無(wú)法綁定到相同的源IP地址和源端口(即源地址和源端口號(hào)均相同)。只要源端口號(hào)不相同,那么源地址實(shí)際上沒(méi)什么關(guān)系。將socket A綁定到地址A和端口X (A:X),socket B綁定到地址B和端口Y (B:Y),只要X != Y,那么這種綁定都是可行的。然而當(dāng)X==Y的時(shí)候只要A != B,這種綁定方式也仍然可行。記住:一個(gè)socket可能綁定到本地"any address"。例如一個(gè)socket綁定為 0.0.0.0:21,那么它同時(shí)綁定了所有的本地地址,在這種情況下,不論其它的socket選擇什么特定的IP地址,它們都無(wú)法綁定到21端口,因?yàn)?.0.0.0和所有的本地地址都會(huì)沖突。

SO_REUSEADDR

如果在綁定一個(gè)socket之前設(shè)置了SO_REUSEADDR,除非兩個(gè)socket綁定的源地址和端口號(hào)都一樣,那么這兩個(gè)綁定都是可行的。也許你會(huì)疑惑這跟之前的有什么不一樣?關(guān)鍵是SO_REUSEADDR改變了在處理源地址沖突時(shí)對(duì)通配地址的處理方式。

當(dāng)沒(méi)有設(shè)置SO_REUSEADDR的時(shí)候,socket A先綁定到0.0.0.0:21,然后socket B綁定到192.168.0.1:21的時(shí)候?qū)?huì)失敗(EADDRINUSE錯(cuò)誤),因?yàn)?.0.0.0意味著"任意本地IP地址”,也就是"所有本地IP地址“,因此包括192.168.0.1在內(nèi)的所有IP地址都被認(rèn)為是已經(jīng)使用了。但是在設(shè)置SO_REUSEADDR之后socket B的綁定將會(huì)成功,因?yàn)?.0.0.0和192.168.0.1事實(shí)上不是同一個(gè)IP地址,一個(gè)是代表所有地址的通配地址,另一個(gè)是一個(gè)具體的地址。注意上面的表述對(duì)于socket A和socket B的綁定順序是無(wú)關(guān)的,沒(méi)有設(shè)置SO_REUSEADDR,它們將失敗,設(shè)置了SO_REUSEADDR,它將成功。

下面給出了一個(gè)表格列出了所有的可能組合:
?

SO_REUSEADDR socket A socket B Result ---------------------------------------------------------------------ON/OFF 192.168.0.1:21 192.168.0.1:21 Error (EADDRINUSE)ON/OFF 192.168.0.1:21 10.0.0.1:21 OKON/OFF 10.0.0.1:21 192.168.0.1:21 OKOFF 0.0.0.0:21 192.168.1.0:21 Error (EADDRINUSE)OFF 192.168.1.0:21 0.0.0.0:21 Error (EADDRINUSE)ON 0.0.0.0:21 192.168.1.0:21 OKON 192.168.1.0:21 0.0.0.0:21 OKON/OFF 0.0.0.0:21 0.0.0.0:21 Error (EADDRINUSE) 現(xiàn)在我們知道SO_REUSEADDR對(duì)通配地址有影響,但這不是它唯一影響到的方面。還有一個(gè)眾所周知的影響同時(shí)也是大多數(shù)人在服務(wù)器程序上使用SO_REUSEADDR的首要原因。為了了解其它SO_REUSEADDR重要的使用方式,我們需要深入了解TCP協(xié)議的工作方式。 一個(gè)socket有一個(gè)發(fā)送緩沖區(qū),當(dāng)調(diào)用send()函數(shù)成功后,這并不意味著所有數(shù)據(jù)都真正被發(fā)送出去了,它只意味著數(shù)據(jù)都被送到了發(fā)送緩沖區(qū)中。對(duì)于UDP socket來(lái)說(shuō),如果不是立刻發(fā)送的話,數(shù)據(jù)通常也會(huì)很快的發(fā)送出去,但對(duì)于TCP socket,在數(shù)據(jù)加入到緩沖區(qū)和真正被發(fā)送出去之間的時(shí)延會(huì)相當(dāng)長(zhǎng)。這就導(dǎo)致當(dāng)我們close一個(gè)TCP socket的時(shí)候,可能在發(fā)送緩沖區(qū)中保存著等待發(fā)送的數(shù)據(jù)(由于send()成功返回,因此你也許認(rèn)為數(shù)據(jù)已經(jīng)被發(fā)送了)。如果TCP的實(shí)現(xiàn)是立刻關(guān)閉socket,那么所有這些數(shù)據(jù)都會(huì)丟失而你的程序根本不可能知道。TCP被稱(chēng)為可靠協(xié)議,像這種丟失數(shù)據(jù)的方式就不那么可靠了。這也是為什么當(dāng)我們close一個(gè)TCP socket的時(shí)候,如果它仍然有數(shù)據(jù)等待發(fā)送,那么該socket會(huì)進(jìn)入TIME_WAIT狀態(tài)(一般都是在服務(wù)器端主動(dòng)關(guān)閉socket的情況下會(huì)發(fā)生)。這種狀態(tài)將持續(xù)到數(shù)據(jù)被全部發(fā)送或者發(fā)生超時(shí)。 在內(nèi)核徹底關(guān)閉socket之前等待的總時(shí)間(不管是否有數(shù)據(jù)在發(fā)送緩沖區(qū)中等待發(fā)送)叫做Linger Time。Linger Time在大部分系統(tǒng)上都是一個(gè)全局性的配置項(xiàng)而且在默認(rèn)情況下時(shí)間相當(dāng)長(zhǎng)(在大部分系統(tǒng)上是兩分鐘)。當(dāng)然對(duì)于每個(gè)socket我們也可以使用socket選項(xiàng)SO_LINGER進(jìn)行配置,可以將等待時(shí)間設(shè)置的更長(zhǎng)一點(diǎn)兒或更短一點(diǎn)兒甚至禁用它。禁用Linger Time絕對(duì)是一個(gè)壞主意,雖然優(yōu)雅的關(guān)閉socket是一個(gè)稍微復(fù)雜的過(guò)程并且涉及到來(lái)回的發(fā)送數(shù)據(jù)包(以及在數(shù)據(jù)包丟失后重發(fā)它們),并且這個(gè)過(guò)程還受到Linger Time的限制。如果禁用Linger Time,socket可能丟失的不僅僅是待發(fā)送的數(shù)據(jù),而且還會(huì)粗暴的關(guān)閉socket,在絕大部分情況下,都不應(yīng)該這樣使用。而且如果你用SO_LINGER禁用了Linger Time,而你的程序在顯式的關(guān)閉socket之前就終止的話,BSD仍然會(huì)等待,而不管已經(jīng)禁用了它。這種情況的一個(gè)例子就是你的程序調(diào)用了exit() 、或者進(jìn)程被信號(hào)殺死。這樣的話,不管在什么情況下,你都無(wú)法對(duì)某一個(gè)socket禁用linger了。 ?問(wèn)題在于,系統(tǒng)是怎樣看待TIME_WAIT狀態(tài)的?如果SO_REUSEADDR還沒(méi)有設(shè)置,一個(gè)處在TIME_WAIT的socket仍然被認(rèn)為綁定在源地址和端口,任何其它的試圖在同樣的地址和端口上綁定一個(gè)socket行為都會(huì)失敗直到原來(lái)的socket真正的關(guān)閉了,這通常需要等待Linger Time的時(shí)長(zhǎng)。所以不要指望在一個(gè)socket關(guān)閉后立刻將源地址和端口綁定到新的socket上,在絕大部分情況下,這種行為都會(huì)失敗。然而,在設(shè)置了SO_REUSEADDR之后試圖這樣綁定(綁定相同的地址和端口)僅僅只會(huì)被忽略,而且你可以將相同的地址綁定到不同的socket上。注意當(dāng)一個(gè)socket處于TIME_WAIT狀態(tài),而你試圖將它綁定到相同的地址和端口,這會(huì)導(dǎo)致未預(yù)料的結(jié)果,因?yàn)樘幱赥IME_WAIT狀態(tài)的socket仍在"工作",幸運(yùn)的是這種情況極少發(fā)生。 ?對(duì)于SO_REUSEADDR你需要知道的最后一點(diǎn)是只有在你想綁定的socket開(kāi)啟了地址重用之后上面的才會(huì)生效,不過(guò)這并不需要檢查之前已經(jīng)綁定或處于TIME_WAIT的socket在它們綁定的時(shí)候是否也設(shè)置這個(gè)選項(xiàng)。也就是說(shuō),綁定的成功與否只會(huì)檢查當(dāng)前bind的socket是否開(kāi)啟了這個(gè)標(biāo)志,不會(huì)查看其它的socket。

SO_REUSEPORT

SO_REUSEPORT的含義與絕大部分人對(duì)SO_REUSEADDR的理解一樣。基本上說(shuō)來(lái),SO_REUSEPORT允許你將多個(gè)socket綁定到相同的地址和端口只要它們?cè)诮壎ㄖ岸荚O(shè)置了SO_REUSEPORT。如果第一個(gè)綁定某個(gè)地址和端口的socket沒(méi)有設(shè)置SO_REUSEPORT,那么其他的socket無(wú)論有沒(méi)有設(shè)置SO_REUSEPORT都無(wú)法綁定到該地址和端口直到第一個(gè)socket釋放了綁定。
? ? SO_REUSEPORT并不表示SO_REUSEADDR。這意味著如果一個(gè)socket在綁定時(shí)沒(méi)有設(shè)置SO_REUSEPORT,那么同預(yù)期的一樣,其它的socket對(duì)相同地址和端口的綁定會(huì)失敗,但是如果綁定相同地址和端口的socket正處在TIME_WAIT狀態(tài),新的綁定也會(huì)失敗。當(dāng)有個(gè)socket綁定后處在TIME_WAIT狀態(tài)(釋放時(shí))時(shí),為了使得其它socket綁定相同地址和端口能夠成功,需要設(shè)置SO_REUSEADDR或者在這兩個(gè)socket上都設(shè)置SO_REUSEPORT。當(dāng)然,在socket上同時(shí)設(shè)置SO_REUSEPORT和SO_REUSEADDR也是可行的。
? ? 關(guān)于SO_REUSEPORT除了它在被添加到系統(tǒng)的時(shí)間比SO_REUSEPORT晚就沒(méi)有其它需要說(shuō)的了,這也是為什么在有些系統(tǒng)的socket實(shí)現(xiàn)上你找不到這個(gè)選項(xiàng),因?yàn)檫@些系統(tǒng)的代碼都是在這個(gè)選項(xiàng)被添加到BSD之前fork了BSD,這樣就不能將兩個(gè)socket綁定到真正相同的“地址” (address+port)。

Connect() Returning EADDRINUSE?

? ? ? 絕大部分人都知道bind()可能失敗返回EADDRINUSE,然而當(dāng)你開(kāi)始使用地址重用,你可能會(huì)碰到奇怪的情況:connect()失敗返回同樣的錯(cuò)誤EADDRINUSE。怎么會(huì)出現(xiàn)這種情況了? 一個(gè)遠(yuǎn)端地址畢竟是connect添加到socket上的,怎么會(huì)已經(jīng)被使用了? 將多個(gè)socket連接到相同的遠(yuǎn)端地址從來(lái)沒(méi)有出現(xiàn)過(guò)這樣的情況,這是為什么了?
? ? ?正如我在開(kāi)頭說(shuō)過(guò)的,一個(gè)連接是被一個(gè)五元組定義的。同樣我也說(shuō)了任意兩個(gè)連接的五元組不能完全一樣,因?yàn)檫@樣的話內(nèi)核就沒(méi)辦法區(qū)分這兩個(gè)連接了。然而,在地址重用的情況下,你可以把同協(xié)議的兩個(gè)socket綁定到完全相同的源地址和源端口,這意味著五元組中已經(jīng)有三個(gè)元素相同了(協(xié)議,源地址,源端口)。如果你嘗試將這些socket連接到同樣的目的地址和目的端口,你就創(chuàng)建了兩個(gè)完全相同的連接。這是不行的,至少對(duì)TCP不行(UDP實(shí)際上沒(méi)有真實(shí)的連接)。如果數(shù)據(jù)到達(dá)這兩個(gè)連接中的任何一個(gè),那么系統(tǒng)將無(wú)法區(qū)分?jǐn)?shù)據(jù)到底屬于誰(shuí)。因此當(dāng)源地址和源端口相同時(shí),目的地址或者目的端口必須不同,否則內(nèi)核無(wú)法進(jìn)行區(qū)分,這種情況下,connect()將在第二個(gè)socket嘗試連接時(shí)返回EADDRINUSE。
?Linux 3.9加入了SO_REUSEPORT。這個(gè)選項(xiàng)允許多個(gè)socket(TCP or UDP)不管是監(jiān)聽(tīng)socket還是非監(jiān)聽(tīng)socket只要都在綁定之前都設(shè)置了它,那么就可以綁定到完全相同的地址和端口。為了阻止"port 劫持"有一個(gè)特別的限制:所有希望共享源地址和端口的socket都必須擁有相同的有效用戶id。因此一個(gè)用戶就不能從另一個(gè)用戶那里"偷取"端口。另外,內(nèi)核在處理SO_REUSEPORT socket的時(shí)候使用了其它系統(tǒng)上沒(méi)有用到的"特別魔法":對(duì)于UDP socket,內(nèi)核嘗試平均的轉(zhuǎn)發(fā)數(shù)據(jù)報(bào),對(duì)于TCP監(jiān)聽(tīng)socket,內(nèi)核嘗試將新的客戶連接請(qǐng)求(由accept返回)平均的交給共享同一地址和端口的socket(監(jiān)聽(tīng)socket)。這意味著在其他系統(tǒng)上socket收到一個(gè)數(shù)據(jù)報(bào)或連接請(qǐng)求或多或少是隨機(jī)的,但是linux嘗試優(yōu)化分配。例如:一個(gè)簡(jiǎn)單的服務(wù)器程序的多個(gè)實(shí)例可以使用SO_REUSEPORT socket實(shí)現(xiàn)一個(gè)簡(jiǎn)單的負(fù)載均衡,因?yàn)閮?nèi)核已經(jīng)把復(fù)制的分配都做了。 2015年12月15日00:34:22

總結(jié)

以上是生活随笔為你收集整理的SO_REUSEADDR SO_REUSEPORT 解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 玖玖国产精品视频 | 色综合av在线 | 日韩三级麻豆 | 亚洲人成电影网 | 国产青草视频在线观看 | 岛国大片在线免费观看 | 日本女优一区 | 日韩黄色三级视频 | 午夜激情啪啪 | 亚洲区成人 | 成人在线免费电影 | wwwxxx黄色片 | 伊人影片| 桃谷绘里香在线播放 | 特级特黄aaaa免费看 | 国产成人99久久亚洲综合精品 | 伊伊综合网 | 999这里只有精品 | 99riav国产精品 | 成人欧美精品一区二区 | 中文字幕 欧美日韩 | 国产无套内射又大又猛又粗又爽 | 成人动漫免费在线观看 | 少妇在线视频 | 在线观看国产一区二区三区 | 毛片无码免费无码播放 | 欧美体内she精高潮 日韩一区免费 | 天天色天天射综合网 | 国产成人无码精品久久久久久 | 豆国产97在线 | 亚洲 | 国产免费999 | 毛片一级在线观看 | 激情二区 | www国产一区 | 欧洲av一区二区三区 | 国产一二三区在线视频 | 真实的国产乱xxxx在线91 | 国产成年妇视频 | 欧美极品在线视频 | 乡村性满足hd | 日本一区二区三区欧美 | 欧美交 | 原创少妇半推半就88av | 丁香八月婷婷 | 夜色网| 性爱一级视频 | 欧美日韩一区精品 | 国产18页 | 国内精品久久久久久久久久 | 日韩欧美一区二区三区在线观看 | 免费在线国产精品 | 偷拍超碰 | 天堂视频在线 | 波多野结衣视频观看 | 久久久久久国产精品三级玉女聊斋 | 欧美高清性xxxxhd | 17c在线观看 | 无码精品视频一区二区三区 | 亚洲乱码国产乱码精品精98午夜 | 香蕉影院在线 | 一级伦理片 | 91最新在线| www.狠狠艹| 成人看片网 | 久久国产99 | 久草一区二区 | 欧美精品入口蜜桃 | 亚洲成人另类 | 涩涩视频免费在线观看 | 亚洲av鲁丝一区二区三区 | 亚洲美女一区二区三区 | 亚洲三级精品 | 欧美波霸影院 | 精品少妇久久久久久888优播 | a国产| 天堂在线播放 | 亚洲毛片网 | 国产夜色精品一区二区av | 波多野结衣一区二 | 日韩成人在线视频观看 | 97精品人人a片免费看 | 日韩精品成人在线观看 | 国产永久免费无遮挡 | 我们俩电影网mp4动漫官网 | 麻豆免费电影 | 青春草在线视频免费观看 | 免费看的黄色小视频 | av老司机在线观看 | 特黄在线| 国产精品黄在线观看 | 亚洲一区二区三区四区在线播放 | ass极品国模人体欣赏 | 亚洲av片一区二区三区 | 光棍天堂av | 国产一区在线视频观看 | 天天射夜夜撸 | 国产精品亚洲а∨天堂免在线 | 妻子的性幻想 | 99久久精品国产色欲 |