日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SO_REUSEADDR 與 SO_REUSEPORT是什么?

Linux愛好者 ? 來源:187J3X1 ? 作者:187J3X1 ? 2020-12-11 16:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

SO_REUSEPORT選項在Linux 3.9被引入內(nèi)核,在這之前也有一個很像的選項SO_REUSEADDR。

如果你不太清楚這兩者的區(qū)別和聯(lián)系,建議搜索 How do SO_REUSEADDR and SO_REUSEPORT differ?。

如果不想讀,那么下面這一節(jié)算是為懶人準備的。

SO_REUSEADDR 與 SO_REUSEPORT 是什么?

TCP/UDP用五元組唯一標識一個連接。

任何時候,兩條連接的五元組都不能完全相同,否則當收到一個報文時,協(xié)議棧沒辦法判斷它是屬于哪個連接的。

五元組{, , , , }

五元組里,protocol在創(chuàng)建socket時確定,在bind()時確定,在connect()時確定。

當然,bind()和connect()在一些時候并不需要顯式使用,不過這不在本文的討論范圍里。

那么,如果對socket設置了SO_REUSEADDR和SO_REUSEPORT選項,它們什么時候起作用呢?

答案是bind(),也就在確定時。

不同操作系統(tǒng)內(nèi)核對待SO_REUSEADDR和SO_REUSEPORT的行為有少許差異,但它們都源自BSD。

因此,接下來就以BSD的實現(xiàn)為標準進行說明。

SO_REUSEADDR

假設我現(xiàn)在需要bind()將socketA綁定到A:X,將socketB綁定到B:Y(不考慮X=0或者Y=0,因為0表示讓內(nèi)核自動分配端口,一定不會沖突)。

如果X!=Y,那么無論A和B的關(guān)系如何,兩個bind()都會成功。但如果X==Y,那么結(jié)果會是下面這樣:

SO_REUSEADDR socketA socketB 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 OK ON/OFF 10.0.0.1:21 192.168.0.1:21 OK OFF 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 OK ON 192.168.1.0:21 0.0.0.0:21 OK ON/OFF 0.0.0.0:21 0.0.0.0:21 Error (EADDRINUSE)

第一列表示是否設置SO_REUSEADDR注,最后一列表示后綁定的socket是否能綁定成功。

注:這里設置的對象是指后綁定的socket(也就是說不關(guān)心前一個是否設置)

可以看出,BSD的實現(xiàn)中SO_REUSEADDR可以讓一個使用通配地址(0.0.0.0),一個使用指定地址(192.168.1.0)的socket同時綁定成功。

SO_REUSEADDR還有一種應用情景:在TCP中存在一個TIME_WAIT狀態(tài),它是指主動關(guān)閉的一端最后停留的階段。

假設socketA綁定到A:X,在完成TCP通信后主動使用close(),進入TIME_WAIT,此時,如果socketB也去綁定A:X,那么同樣會得到EADDRINUSE錯誤,但如果socketB設置了SO_REUSEADDR,那么就可以綁定成功。

SO_REUSEPORT

如果理解了SO_REUSEADDR,那么SO_REUSEPORT就很好理解了,它讓兩個socket可以綁定完全相同的。

SO_REUSEPORT socketA socketB Result --------------------------------------------------------------------- ON 192.168.0.1:21 192.168.0.1:21 OK

提醒一下,以上的結(jié)果都是BSD的結(jié)果,Linux內(nèi)核有一些不一樣的地方,具體表現(xiàn)為

3.9版本支持SO_REUSEPORT,作為Server的TCP Socket一旦綁定到了具體的端口,啟動了LISTEN,即使它之前設置過SO_REUSEADDR, 也不會生效。這一點Linux比BSD更加嚴格

SO_REUSEADDR socketA socketB Result --------------------------------------------------------------------- ON/OFF 192.168.0.1:21 0.0.0.0:21 Error (EADDRINUSE)

3.9版本之前,作為Client的Socket,SO_REUSEADDR選項具有BSD中的SO_REUSEPORT的效果。這一點Linux又比BSD更加寬松。

SO_REUSEADDR socketA socketB Result --------------------------------------------------------------------- ON 192.168.0.2:55555 192.168.0.2:55555 OK

Linux中reuseport的演進

Linux < 3.9

下面看看具體是怎么做的: 內(nèi)核socket使用skc_reuse字段表示是否設置了SO_REUSEADDR

struct sock_common { /* omitted */ unsigned char skc_reuse; /* omitted */ } int sock_setsockopt(struct socket *sock, int level, int optname,... { ...... case SO_REUSEADDR: sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE); break; }

inet_bind_bucket表示一個綁定的端口。

struct inet_bind_bucket { /* omitted */ unsigned short port; signed short fastreuse; int num_owners; struct hlist_node node; struct hlist_head owners; };

上面結(jié)構(gòu)中的fastreuse表示該端口是否支持共享,所有共享該端口的socket掛到owner成員上。在用戶使用bind()時,內(nèi)核使用TCP:inet_csk_get_port(),UDP:udp_v4_get_port()來綁定端口。

/* inet_connection_Sock.c: inet_csk_get_port() */ tb_found: if (!hlist_empty(&tb->owners)) { ...... if (tb->fastreuse > 0 && sk->sk_reuse && sk->sk_state != TCP_LISTEN && smallest_size == -1) { goto success;

所以,當該端口支持共享,且socket也設置了SO_REUSEADDR并且不為LISTEN狀態(tài)時,此次bind()可以成功。

3.9 =< Linux < 4.5

3.9版本內(nèi)核增加了對SO_REUSEPORT的支持,listener可以綁定到相同的了。

這個時候,當Server收到Client發(fā)送的SYN報文時,會選擇其中一個socket進行響應。

具體到實現(xiàn),3.9版本擴展了sock_common,將原來記錄skc_reuse進行了拆分.

struct sock_common { unsigned short skc_family; volatile unsigned char skc_state; - unsigned char skc_reuse; + unsigned char skc_reuse:4; + unsigned char skc_reuseport:4; @@ int sock_setsockopt(struct socket *sock, int level, int optname, case SO_REUSEADDR: sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE); break; + case SO_REUSEPORT: + sk->sk_reuseport = valbool; + break;

然后對inet_bind_bucket也相應進行了擴展

struct inet_bind_bucket { /* omitted */ unsigned short port; - signed short fastreuse; + signed char fastreuse; + signed char fastreuseport; + kuid_t fastuid;

而在綁定端口時,增加了一個隊reuseport的通過條件

/* inet_connection_sock.c: inet_csk_get_port() */ tb_found: if (sk->sk_reuse == SK_FORCE_REUSE) goto success; - if (tb->fastreuse > 0 && - sk->sk_reuse && sk->sk_state != TCP_LISTEN && + if (((tb->fastreuse > 0 && + sk->sk_reuse && sk->sk_state != TCP_LISTEN) || + (tb->fastreuseport > 0 && + sk->sk_reuseport && uid_eq(tb->fastuid, uid))) && smallest_size == -1) { goto success;

而當Client的SYN報文到達時,Server會首先根據(jù)本地端口(SYN報文的)計算出一條hash沖突鏈,然后遍歷該鏈表上的所有Socket,根據(jù)四元組匹配程度進行打分;

如果使能了reuseport,那么可能有多個Socket都將拿到最高分,此時內(nèi)核將隨機選擇一個進行后續(xù)處理。

/* inet_hashtables.c */ struct sock *__inet_lookup_listener(struct......) { struct sock *sk, *result; unsigned int hash = inet_lhashfn(net, hnum); struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; // 根據(jù)本地端口找到hash沖突鏈 /* code omitted */ result = NULL; hiscore = 0; sk_nulls_for_each_rcu(sk, node, &ilb->head) { score = compute_score(sk, net, hnum, daddr, dif); // 根據(jù)匹配程度進行打分 if (score > hiscore) { result = sk; hiscore = score; reuseport = sk->sk_reuseport; if (reuseport) { phash = inet_ehashfn(net, daddr, hnum, saddr, sport); matches = 1; // 如果是reuseport 則累計多少個socket滿足 } } else if (score == hiscore && reuseport) { matches++; if (reciprocal_scale(phash, matches) == 0) result = sk; phash = next_pseudo_random32(phash); } } /* * if the nulls value we got at the end of this lookup is * not the expected one, we must restart lookup. * We probably met an item that was moved to another chain. */ return result; }

舉個栗子,假設內(nèi)核有4條listening socket的hash沖突鏈,然后用戶建立了4個Server:A、B、C、D,監(jiān)聽的地址和端口如下圖所示,A和B使能了SO_REUSEPORT。

沖突鏈是以端口為Key的,因此A、B、D會掛到同一條沖突鏈上。

如果此時收到對端一個SYN報文<192.168.10.1, 21>,那么內(nèi)核會遍歷listening_hash[0],為上面的7個socket進行打分,而由于B監(jiān)聽的是精確的地址,所以B的得分會比A高,內(nèi)核最終選擇出一個SocketB進行后續(xù)處理。

89f4964a-2eb2-11eb-a64d-12bb97331649.png

4.5 < Linux

從上面的例子可以看出,當收到SYN報文時,內(nèi)核一定會遍歷一條完整hash沖突鏈,為每一個socket進行打分,這稍微有些多余。

因此,在4.5版本中,內(nèi)核引入了reuseport groups,它將綁定到同一個IP和Port,并且設置了SO_REUSEPORT選項的socket組織到一個group內(nèi)部。

8a34dac0-2eb2-11eb-a64d-12bb97331649.png

--- a/include/net/sock.h +++ b/include/net/sock.h @@ -318,6 +318,7 @@ struct cg_proto; * @sk_error_report: callback to indicate errors (e.g. %MSG_ERRQUEUE) * @sk_backlog_rcv: callback to process the backlog * @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0 + * @sk_reuseport_cb: reuseport group container */ struct sock { /* @@ -453,6 +454,7 @@ struct sock { int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); void (*sk_destruct)(struct sock *sk); + struct sock_reuseport __rcu *sk_reuseport_cb; };

這個特性在4.5版本只支持UDP,而在4.6版本開始支持TCP(patch)。

這樣在查找listen socket時,內(nèi)核將不用再遍歷整個沖突鏈,而是在找到一個合格的socket時,如果它設置了SO_REUSEPORT,就直接找到它所屬的reuseport group,從中選擇一個進行后續(xù)處理。

@@ -215,6 +217,7 @@ struct sock *__inet_lookup_listener(struct net *net, unsigned int hash = inet_lhashfn(net, hnum); struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; int score, hiscore, matches = 0, reuseport = 0; + bool select_ok = true; u32 phash = 0; rcu_read_lock(); @@ -230,6 +233,15 @@ begin: if (reuseport) { phash = inet_ehashfn(net, daddr, hnum, saddr, sport); + if (select_ok) { + struct sock *sk2; + sk2 = reuseport_select_sock(sk, phash, + skb, doff); + if (sk2) { + result = sk2; + goto found; + } + } matches = 1; } }

責任編輯:lq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    4

    文章

    1476

    瀏覽量

    43101
  • Linux
    +關(guān)注

    關(guān)注

    88

    文章

    11825

    瀏覽量

    219618

原文標題:Linux 內(nèi)核中 reuseport 的演進

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    矽力杰 SQ33261 SO8 4.2-38V 輸入規(guī)格書

    控制器,采用 SO8 封裝,支持 4.2-38V 寬電壓供電,DA/DB 引腳支持 200V 高壓漏極檢測,兼容 CCM/DCM 工作模式,具備 15ns 超快關(guān)斷傳播延遲,柵極驅(qū)動能力達 0.3A
    發(fā)表于 03-29 16:57 ?0次下載

    矽力杰 SQ33260 SO8 4.2-38V 輸入規(guī)格書

    控制器,采用 SO8 封裝,支持 4.2-38V 寬電壓供電,DA/DB 引腳支持 200V 高壓漏極檢測,兼容 CCM/DCM 工作模式,具備 15ns 超快關(guān)斷傳播延遲,柵極驅(qū)動能力達 0.3A
    發(fā)表于 03-29 16:55 ?0次下載

    SGM2526SF/SGM2526SO可編程電流限制開關(guān):特性、應用與設計要點

    SGM2526SF/SGM2526SO可編程電流限制開關(guān):特性、應用與設計要點 作為電子工程師,在設計電路時,常常需要為系統(tǒng)選擇合適的電流限制開關(guān),來保障電路的穩(wěn)定運行。今天,我們就來詳細探討
    的頭像 發(fā)表于 03-24 17:50 ?1047次閱讀

    如何在 VF2 上玩 Minecraft 的分步指南

    /liblwjgl.so .cp ~/lwjgl3-riscv-existing/bin/libs/native/linux/riscv64/org/lwjgl/glfw/libglfw.so .cp
    發(fā)表于 02-27 07:45

    無法打開 starfive:/usr/lib/dri/starfive_dri.so怎么解決?

    我創(chuàng)建了一個干凈的debootstraped Debian 圖像。啟動 X 會話時,我收到一個關(guān)于丟失的奇怪錯誤starfive_dri.所以.會話仍會開始。但我想知道可以在哪里聲明這樣的自定義/供應商庫。StarFive 是否提供此庫的源代碼或軟件包?雖然提供了一些與 GPU 相關(guān)的庫這里,我找不到starfive_dri.所以在。 root@host:~# startxX.Org X Server 1.21.1.7X Protocol Version 11, Revision 0Current Operating System: Linux DietPi 5.15.102 #1 SMP Tue Mar 14 15:28:55 UTC 2023 riscv64Kernel command line: root=PARTUUID=c3534437-01 rootfstype=ext4 rootwait earlycon console=ttyS0,115200 console=tty0 consoleblank=0 net.ifnames=0xorg-server 2:21.1.7-1 (https://www.debian.org/support)Current version of pixman: 0.42.2Before reporting problems, check http://wiki.x.orgto make sure that you have the latest version.Markers: (--) probed, (**) from config file, (==) default setting,(++) from command line, (!!) notice, (II) informational,(WW) warning, (EE) error, (NI) not implemented, (??) unknown.(==) Log file: "/var/log/xorg.0.log", Time: Tue Mar 14 22:40:39 2023(==) Using config directory: "/etc/X11/xorg.conf.d"(==) Using system config directory "/usr/share/X11/xorg.conf.d"MESA-LOADER: failed to open starfive: /usr/lib/dri/starfive_dri.所以: cannot open shared object file: No such file or directory (search paths /usr/lib/riscv64-linux-gnu/dri:$${ORIGIN}/dri:/usr/lib/dri, suffix _dri)failed to load driver: starfive^Cxinit: connection to X server lostwaiting for X server to shut down .(II) Server terminated successfully (0). Closing log file.xinit: unexpected signal 2root@host:~#我打斷了 X 會話,如^C,在它運行了幾分鐘之后。由于系統(tǒng)是遠程的,我無法測試桌面是否真的顯示在附加的屏幕上。遠程團隊成員稍后將執(zhí)行此作.這/var/log/xorg.0.log不提供更多相關(guān)細節(jié)。
    發(fā)表于 02-10 08:08

    MDD品牌三極管MMBT4403數(shù)據(jù)手冊

    SO T-23開關(guān)晶體管
    發(fā)表于 01-05 09:53 ?0次下載

    探索CYTVII-B-E-100-SO評估板:功能、操作與連接全解析

    探索CYTVII-B-E-100-SO評估板:功能、操作與連接全解析 在電子設計領(lǐng)域,評估板是驗證和開發(fā)新設備功能的重要工具。今天,我們將深入探討CYTVII-B-E-100-SO評估板,它是
    的頭像 發(fā)表于 12-19 10:30 ?548次閱讀

    Amphenol ICC DDR5 SO - DIMM連接器:高速高密度的理想之選

    Amphenol ICC DDR5 SO - DIMM連接器:高速高密度的理想之選 在當今高速發(fā)展的電子科技領(lǐng)域,內(nèi)存連接器的性能對于系統(tǒng)的整體表現(xiàn)起著至關(guān)重要的作用。Amphenol ICC推出
    的頭像 發(fā)表于 12-12 11:15 ?707次閱讀

    DDR5設計指南(二):什么是CAMM2?

    的? SO-DIMM ?標準。 CAMM2 的主要特點和優(yōu)勢: 更薄、更節(jié)省空間: CAMM2 模組的設計非常纖薄,它平貼在主板上,而不是像 SO-DIMM 那樣傾斜插入。與 SO-DIMM 相比,它可以節(jié)省高
    的頭像 發(fā)表于 10-28 11:15 ?6389次閱讀
    DDR5設計指南(二):什么是CAMM2?

    擎天柱如何配置程序

    //sbit SPI_CE= P4^0; //sbit SPI_SO= P4^2; //sbit SPI_SI= P4^1; //sbit SPI_SCK = P4^3; sbit SPI_CE
    發(fā)表于 10-07 20:10

    昂科燒錄器支持Microchip微芯科技的8位CMOS微控制器PIC16F54-I/SO

    芯片燒錄領(lǐng)導者昂科技術(shù)在發(fā)布新版燒錄軟件的同時,宣布擴展了兼容芯片型號列表。新增型號里有了微芯科技的8位CMOS微控制器PIC16F54-I/SO,這款芯片已得到昂科通用燒錄平臺AP8000通用
    的頭像 發(fā)表于 08-05 09:38 ?1240次閱讀
    昂科燒錄器支持Microchip微芯科技的8位CMOS微控制器PIC16F54-I/<b class='flag-5'>SO</b>

    插座對不上?電壓飄忽不定?優(yōu)比施UPS一鍵搞定,海外用電So Easy!

    UPS
    上海優(yōu)比施電子科技有限公司
    發(fā)布于 :2025年08月05日 08:48:32

    東芝推出全新車載光繼電器TLX9165T

    東芝電子元件及存儲裝置株式會社(“東芝”)今日宣布,推出一款車載光繼電器[1]“TLX9165T”,其采用10引腳SO16L-T封裝,支持輸出耐壓1800V(最小值)的高壓車載電池。該產(chǎn)品于今日開始支持批量出貨。
    的頭像 發(fā)表于 07-18 14:14 ?1536次閱讀
    東芝推出全新車載光繼電器TLX9165T

    【Milk-V Duo S 開發(fā)板免費體驗】SDK系統(tǒng)構(gòu)建體驗

    ; references the file "/usr/lib/x86_64-linux-gnu/libEGL.so"安裝sudo apt-get install libegl1
    發(fā)表于 07-08 14:41

    在linux環(huán)境下 軟件啟動失敗怎么解決?

    anyway. /usr/lib/x86_64-linux-gnu/libproxy/libpxbackend-1.0.so: undefined symbol
    發(fā)表于 06-23 07:37
    万载县| 西青区| 闽清县| 呈贡县| 衡南县| 昌平区| 元朗区| 霞浦县| 印江| 栖霞市| 蛟河市| 康平县| 左权县| 中卫市| 木兰县| 新乡县| 武胜县| 青阳县| 建昌县| 卢湾区| 龙游县| 新郑市| 西盟| 无为县| 芦山县| 西城区| 句容市| 安溪县| 开封县| 武威市| 江永县| 江孜县| 桂林市| 伊春市| 周宁县| 高密市| 阿巴嘎旗| 阿克陶县| 灌阳县| 西安市| 邢台市|