自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

90% 的人答錯(cuò)!TCP 和 UDP 可以使用同一個(gè)端口嗎?(字節(jié)面試真題)

網(wǎng)絡(luò)
今天我要和大家分享一道字節(jié)跳動(dòng)的經(jīng)典面試題:TCP 和 UDP 可以使用同一個(gè)端口嗎。

大家好,我是小康。今天我要和大家分享一道字節(jié)跳動(dòng)的經(jīng)典面試題:TCP 和 UDP 可以使用同一個(gè)端口嗎?

看似簡單,實(shí)則暗藏玄機(jī)的網(wǎng)絡(luò)問題!

乍一聽,你可能想直接回答"可以"或"不可以"就完事了。

但等等,這個(gè)問題遠(yuǎn)沒有那么簡單! 為什么這個(gè)問題能成為各大廠面試的熱門話題?

因?yàn)樗睋艟W(wǎng)絡(luò)協(xié)議的核心,展示了 TCP/UDP 端口管理背后的巧妙設(shè)計(jì)。 今天,我們就來聊聊這個(gè)問題背后的秘密。

問題拆解:五個(gè)維度的思考

要全面回答這個(gè)問題,我們需要從五個(gè)不同角度來思考:

  • 協(xié)議層面:TCP 和 UDP 是否可共享同一端口號(hào)?
  • 客戶端 TCP 進(jìn)程:多個(gè)進(jìn)程能否共享一個(gè) TCP 端口?
  • 客戶端 UDP 進(jìn)程:多個(gè)進(jìn)程能否共享一個(gè) UDP 端口?
  • 服務(wù)端 TCP 進(jìn)程:多個(gè)進(jìn)程能否監(jiān)聽同一 TCP 端口?
  • 服務(wù)端 UDP 進(jìn)程:多個(gè)進(jìn)程能否監(jiān)聽同一 UDP 端口?

讓我們逐一解析。

1. 協(xié)議層面:TCP 和 UDP 能否共享端口?

答案:能!這是網(wǎng)絡(luò)設(shè)計(jì)的基本常識(shí)。

先來拆解下這個(gè)問題的本質(zhì):

TCP 和 UDP 是兩個(gè)完全不同的"世界"。操作系統(tǒng)為它們分別準(zhǔn)備了各自的 65536 個(gè)端口(0-65535)。就像兩棟一模一樣的大樓,每棟樓都有 65536 個(gè)房間,一棟給 TCP 住,一棟給 UDP 住。

同一個(gè)端口號(hào)在 TCP 和 UDP 上是完全獨(dú)立的兩個(gè)資源!比如:

  • TCP 的 53號(hào)端口 是一回事
  • UDP 的 53號(hào)端口 是另一回事
  • 它們互不干擾,可以同時(shí)被使用

(1) 經(jīng)典例子:DNS服務(wù)

最好的例子就是 DNS 服務(wù)器,它同時(shí)使用 TCP 和 UDP 的53端口:

  • UDP 53端口:處理小型查詢(大多數(shù)日常DNS查詢)
  • TCP 53端口:處理大型查詢和區(qū)域傳輸

你可以用netstat -tuln | grep :53命令親自驗(yàn)證這一點(diǎn):

tcp   0   0 0.0.0.0:53    0.0.0.0:*   LISTEN
udp   0   0 0.0.0.0:53    0.0.0.0:*

當(dāng)你的電腦查詢網(wǎng)站域名時(shí),通常通過 UDP 發(fā)送請(qǐng)求。如果數(shù)據(jù)太大(超過 512 字節(jié)),則自動(dòng)切換到 TCP。不管哪種情況,服務(wù)器都準(zhǔn)備好了相應(yīng)的 53 端口來接待你!

(2) 端口分配的官方規(guī)則

國際組織 IANA(互聯(lián)網(wǎng)號(hào)碼分配機(jī)構(gòu))負(fù)責(zé)端口分配,他們通常會(huì)這樣做:

  • 把一個(gè)端口號(hào)同時(shí)分配給 TCP 和 UDP 上的同一個(gè)服務(wù)
  • 但服務(wù)可以選擇只用 TCP、只用 UDP 或者兩者都用

比如:

  • 80 端口分配給了 HTTP 服務(wù)
  • 但 HTTP 只使用 TCP 的 80 端口
  • UDP 的 80 端口實(shí)際上處于閑置狀態(tài),可以被其他程序使用

(3) 現(xiàn)實(shí)生活中的端口使用

在實(shí)際應(yīng)用中:

  • 有些服務(wù)同時(shí)使用 TCP/UDP 的同一端口(如 DNS 用 53)
  • 有些服務(wù)只用 TCP(如 HTTP 用 80)
  • 有些服務(wù)只用 UDP(如 SNTP 用 123)

所以,當(dāng)有人問TCP和UDP能否使用同一個(gè)端口號(hào),答案簡單明了:可以!它們是兩個(gè)獨(dú)立的世界,互不干擾。

2. 客戶端 TCP 進(jìn)程:多個(gè)進(jìn)程能否共享一個(gè) TCP 端口?

答案:不能!這是 TCP 通信的基本規(guī)則。

一個(gè)簡單的例子:你的電腦 IP 是 1.1.1.1,如果瀏覽器已經(jīng)用了 8888 端口,那么:

  • 1.1.1.1:8888 這個(gè)組合被瀏覽器獨(dú)占
  • 其他程序不能再用這個(gè)端口,必須用別的端口號(hào)
  • 即使瀏覽器關(guān)閉連接,端口也會(huì)進(jìn)入TIME_WAIT狀態(tài)(持續(xù)1-4分鐘),期間仍然不能被其他程序使用

為什么這樣設(shè)計(jì)?

因?yàn)?TCP 連接由四元組唯一標(biāo)識(shí):[源IP, 源端口, 目標(biāo)IP, 目標(biāo)端口]。如果多個(gè)程序共用源端口,系統(tǒng)就無法區(qū)分返回?cái)?shù)據(jù)該給誰。

但有個(gè)例外:不同IP可以各自使用相同端口。

如果你的電腦有兩個(gè)IP:

  • 普通網(wǎng)卡:1.1.1.1
  • 回環(huán)地址:127.0.0.1

那么:

  • 即使瀏覽器占用了 1.1.1.1:8888
  • 其他程序仍可使用 127.0.0.1:8888

這是因?yàn)椴僮飨到y(tǒng)是按照[IP:端口]組合來管理TCP資源的,不同IP下的相同端口被視為不同資源。

TIME_WAIT狀態(tài)的陷阱:

當(dāng) TCP 連接關(guān)閉后,端口不會(huì)立即釋放,而是進(jìn)入TIME_WAIT狀態(tài)(通常持續(xù) 2MSL,約1-4分鐘)。在這段時(shí)間內(nèi),該端口對(duì)于特定 IP 仍然是被占用的。

這就是為什么有時(shí)候重啟服務(wù)時(shí)會(huì)遇到 bind: Address already in use 的錯(cuò)誤,即使你看不到任何進(jìn)程在使用它。

3. 客戶端 UDP 進(jìn)程:多個(gè)進(jìn)程能否共享一個(gè) UDP 端口?

答案:表面上不能,但細(xì)究起來很有趣!

UDP 的端口使用有兩種完全不同的方式,這導(dǎo)致了不同的端口共享規(guī)則:

(1) 不綁定端口(系統(tǒng)自動(dòng)分配)

如果你的程序只是發(fā) UDP 包,沒有調(diào)用bind()函數(shù):

// 不綁定特定端口,發(fā)送數(shù)據(jù)
sendto(sock, data, len, 0, &server_addr, addr_len);

這種情況下:

  • 發(fā)送數(shù)據(jù)時(shí),系統(tǒng)臨時(shí)分配的端口(比如 8888)確實(shí)被獨(dú)占
  • 但不發(fā)數(shù)據(jù)時(shí),其他程序可以用這個(gè)端口發(fā)送數(shù)據(jù)
  • 問題來了:如果服務(wù)器對(duì) 8888 端口的響應(yīng)回來時(shí),可能被占用這個(gè)端口的其他程序截獲!

這就是 UDP "無連接"特性的真實(shí)寫照。系統(tǒng)不記錄誰在用這個(gè)端口,誰發(fā)了什么,它只負(fù)責(zé)傳遞數(shù)據(jù)包。

這種模式適合"發(fā)了就不管"的單向通信(如日志上報(bào)), 我們將這種模式稱之為 Unconnected UDP。

(2) 顯式綁定端口(使用 bind 函數(shù))

如果你的程序明確綁定了端口:

// 明確綁定8888端口
bind(sock, &local_addr, addr_len);

這種情況下:

  • 8888 端口被完全獨(dú)占,其他程序不能使用它
  • 直到程序結(jié)束并關(guān)閉 socket,這個(gè)端口才會(huì)釋放

進(jìn)一步地,你還可以用connect()指定通信對(duì)象(connect 對(duì) UDP 來說不建立真正連接,而是在內(nèi)核中記錄目標(biāo)地址):

// 指定目標(biāo)服務(wù)器地址
connect(sock, &server_addr, addr_len);

當(dāng)通信雙方都使用綁定的端口通信時(shí),此時(shí) UDP 通信就變得像 TCP 一樣有固定的四元組::

  • 客戶端IP: 1.1.1.1
  • 客戶端端口: 8888
  • 服務(wù)器IP: 2.2.2.2
  • 服務(wù)器端口: 9999

這種"綁了 bind 又 connect "的方式俗稱 Connected UDP,是大多數(shù)需要雙向通信的 UDP 應(yīng)用程序的標(biāo)準(zhǔn)做法。

記?。哼x擇哪種模式不是為了風(fēng)格,而是根據(jù)你的應(yīng)用需求。需要雙向通信?就用 Connected UDP。只是單向發(fā)送數(shù)據(jù)?Unconnected UDP 就夠了。

(3) 代碼對(duì)比:解密兩種模式的本質(zhì)區(qū)別

Unconnected UDP(不安全但靈活):

// 進(jìn)程A
sockA = socket(AF_INET, SOCK_DGRAM, 0);
sendto(sockA, "Hello", 5, 0, &server, sizeof(server));
// 系統(tǒng)分配臨時(shí)端口,如8888

// 同一時(shí)間,進(jìn)程B可能會(huì):
sockB = socket(AF_INET, SOCK_DGRAM, 0);
sendto(sockB, "World", 5, 0, &other_server, sizeof(other_server));
// 如果A不再發(fā)包,系統(tǒng)可能分配8888給B

// 結(jié)果:如果server回復(fù)數(shù)據(jù)到端口8888,可能被進(jìn)程B意外接收

Connected UDP(安全且可控,但依然不保證可靠傳輸):

// 進(jìn)程A
sockA = socket(AF_INET, SOCK_DGRAM, 0);
bind(sockA, &local, sizeof(local));  // 顯式綁定到8888端口
connect(sockA, &server, sizeof(server));  // 關(guān)聯(lián)特定服務(wù)器
send(sockA, "Hello", 5, 0);  // 簡化的發(fā)送

// 進(jìn)程B嘗試使用相同端口
sockB = socket(AF_INET, SOCK_DGRAM, 0);
ret = bind(sockB, &local, sizeof(local));  // 嘗試綁定8888
// 結(jié)果:bind()失敗,返回EADDRINUSE錯(cuò)誤

4. 服務(wù)端 TCP 進(jìn)程:多個(gè)進(jìn)程能否監(jiān)聽同一 TCP 端口?

答案:默認(rèn)不能,但 SO_REUSEADDR 提供了精妙的例外機(jī)制。

TCP 服務(wù)器啟動(dòng)時(shí),最核心的步驟之一就是綁定并監(jiān)聽(Listen)端口。通常情況下,一個(gè) TCP 端口只能被一個(gè)進(jìn)程監(jiān)聽,這確保了連接請(qǐng)求有明確的處理者。但在實(shí)際應(yīng)用中,這種限制有時(shí)過于僵化。這就是為什么操作系統(tǒng)提供了更高級(jí)的端口復(fù)用機(jī)制。

(1) 深入理解 SO_REUSEADDR

SO_REUSEADDR是一個(gè)套接字選項(xiàng),它修改了操作系統(tǒng)處理地址綁定的默認(rèn)行為:

int sock = socket(AF_INET, SOCK_STREAM, 0);
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

為什么叫"Reuse Address"而不是"Reuse Port"?這揭示了其核心機(jī)制:它允許不同進(jìn)程監(jiān)聽同一端口,但要求綁定到不同的 IP 地址或綁定的精確程度不同。簡單說,一個(gè)進(jìn)程可以綁定到具體IP地址,另一個(gè)進(jìn)程則綁定到全部IP地址(通配符地址)。

(2) 精確的綁定優(yōu)先級(jí)規(guī)則

假設(shè)一臺(tái)服務(wù)器有以下IP地址:

  • IP1 = 2.2.2.2 (網(wǎng)卡1)
  • IP2 = 3.3.3.3 (網(wǎng)卡2)
  • IP3 = 127.0.0.1 (回環(huán)接口)

現(xiàn)在我們創(chuàng)建兩個(gè)啟用了SO_REUSEADDR的進(jìn)程:

  • 進(jìn)程A綁定 *:80 (或?qū)懽?.0.0.0:80,表示監(jiān)聽所有接口的 80 端口)
  • 進(jìn)程B綁定 2.2.2.2:80 (明確指定監(jiān)聽網(wǎng)卡1的 80 端口)

系統(tǒng)如何決定哪個(gè)進(jìn)程處理連接?操作系統(tǒng)遵循一個(gè)核心原則:最具體的綁定勝出。

目標(biāo)地址

處理進(jìn)程

原因說明

2.2.2.2:80

進(jìn)程B

進(jìn)程 B 的綁定更具體

3.3.3.3:80

進(jìn)程A

只有進(jìn)程 A 監(jiān)聽此IP

127.0.0.1:80

進(jìn)程A

只有進(jìn)程 A 監(jiān)聽此IP

(3) 自動(dòng)故障轉(zhuǎn)移的隱藏機(jī)制

這種設(shè)計(jì)不僅提供了靈活性,還內(nèi)置了故障轉(zhuǎn)移能力。假設(shè)網(wǎng)卡1 (2.2.2.2) 發(fā)生故障:

┌─────────┐
正常情況:                        │ 進(jìn)程A   │ 監(jiān)聽 *:80
客戶端 ──? 2.2.2.2:80 ──────────?│ 進(jìn)程B   │ 監(jiān)聽 2.2.2.2:80
客戶端 ──? 3.3.3.3:80 ──────────?│ 進(jìn)程A   │
                                └─────────┘

                                ┌─────────┐
網(wǎng)卡1故障:                       │ 進(jìn)程A   │ 
客戶端 ──? 2.2.2.2:80 ──────────?│ 進(jìn)程A   │ 自動(dòng)接管!
客戶端 ──? 3.3.3.3:80 ──────────?│ 進(jìn)程A   │
                                └─────────┘

神奇的是,原本發(fā)往2.2.2.2:80的連接會(huì)自動(dòng)轉(zhuǎn)由進(jìn)程A處理!這是因?yàn)椋?/p>

  • 網(wǎng)卡 1 故障后,進(jìn)程B的具體綁定失效
  • 但操作系統(tǒng)仍然能通過其他網(wǎng)卡接收目標(biāo)為 2.2.2.2 的數(shù)據(jù)包
  • 此時(shí)通配符綁定的進(jìn)程 A 自動(dòng)"繼承"處理權(quán)

這種機(jī)制是高可用系統(tǒng)的基石,無需額外的故障檢測(cè)和切換邏輯。

(4) SO_REUSEADDR 的其他重要功能

除了上述IP綁定的復(fù)用,SO_REUSEADDR還提供了另一個(gè)關(guān)鍵功能:允許綁定處于TIME_WAIT狀態(tài)的地址。

當(dāng)TCP服務(wù)器重啟時(shí),之前的連接可能處于 TIME_WAIT 狀態(tài),導(dǎo)致端口暫時(shí)無法重用。設(shè)置 SO_REUSEADDR 可以立即重新綁定這些端口,而不必等待 TIME_WAIT 超時(shí)(通常為1-4分鐘)。

5. 服務(wù)端 UDP 進(jìn)程:多個(gè)進(jìn)程能否監(jiān)聽同一 UDP 端口?

答案:基本規(guī)則類似 TCP,但 UDP 提供了更強(qiáng)大的 SO_REUSEPORT 選項(xiàng)。

UDP 服務(wù)端的基本端口共享規(guī)則與 TCP 類似(參考前面關(guān)于 TCP 的分析),但 UDP 提供了一個(gè)額外的"超能力"—— SO_REUSEPORT。

(1) SO_REUSEPORT:UDP的秘密武器

SO_REUSEPORT 比 SO_REUSEADDR 更進(jìn)一步,它允許:

  • 多個(gè)進(jìn)程綁定到 完全相同 的IP:端口組合
  • 每個(gè)進(jìn)程都能接收發(fā)往該地址的數(shù)據(jù)包
int sock = socket(AF_INET, SOCK_DGRAM, 0);
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
bind(sock, &addr, sizeof(addr));  // 即使其他進(jìn)程已綁定相同地址,也能成功

(2) 實(shí)現(xiàn)原理:內(nèi)核的負(fù)載均衡機(jī)制

操作系統(tǒng)如何決定將數(shù)據(jù)包發(fā)給哪個(gè)進(jìn)程?

現(xiàn)代 Linux 內(nèi)核使用一個(gè)精心設(shè)計(jì)的哈希算法,基于數(shù)據(jù)包的源地址、源端口、目標(biāo)地址和目標(biāo)端口計(jì)算哈希值,然后根據(jù)哈希結(jié)果選擇一個(gè)接收進(jìn)程。這種設(shè)計(jì)確保:

  • 來自同一客戶端的請(qǐng)求總是被同一個(gè)進(jìn)程處理(會(huì)話一致性)
  • 多個(gè)客戶端的請(qǐng)求被均勻分散到不同進(jìn)程(負(fù)載均衡)

這在多核系統(tǒng)上特別有用 —— 每個(gè) CPU 核心運(yùn)行一個(gè)接收進(jìn)程,克服了單進(jìn)程接收的瓶頸。

(3) 組播與廣播:完美的應(yīng)用場(chǎng)景

SO_REUSEPORT 的另一個(gè)殺手級(jí)應(yīng)用是UDP組播和廣播:

┌─────────┐
                    │ 進(jìn)程A   │
                 ┌─?│         │
組播源            │  └─────────┘
239.1.1.1:8888 ──┤  
                 │  ┌─────────┐
                 └─?│ 進(jìn)程B   │
                    │         │
                    └─────────┘
  • 多個(gè)進(jìn)程可以同時(shí)綁定到組播地址(如224.0.0.1:8888)
  • 當(dāng)組播數(shù)據(jù)到達(dá)時(shí),所有監(jiān)聽進(jìn)程都會(huì)收到完整數(shù)據(jù)包
  • 這與普通 UDP 端口的負(fù)載均衡機(jī)制不同,組播情況下是 數(shù)據(jù)復(fù)制 而非分發(fā)

(4) 為何稱為 REUSEPORT 而非 REUSEADDR?

這個(gè)命名反映了其設(shè)計(jì)重點(diǎn):

  • SO_REUSEADDR:主要關(guān)注不同IP下的相同端口復(fù)用
  • SO_REUSEPORT:真正允許完全相同的IP+端口被多個(gè)進(jìn)程復(fù)用

雖然SO_REUSEPORT也能用于組播地址(如224.0.0.1),但其主要?jiǎng)?chuàng)新在于允許相同普通 IP 地址和端口的真正重用。

總結(jié):看透問題本質(zhì),輕松應(yīng)對(duì)面試

好了,回到最初的面試題:TCP 和 UDP 可以使用同一個(gè)端口嗎?

答案是:可以! 但這只是冰山一角。

通過我們的討論,你現(xiàn)在知道了:

  • TCP 和 UDP 的端口表是完全獨(dú)立的(就像 DNS 同時(shí)用 TCP 和 UDP 的53端口)
  • 客戶端 TCP 端口被一個(gè)進(jìn)程占用后,其他進(jìn)程就別想用了(至少在同一IP下)
  • 客戶端 UDP 端口有兩種用法,不綁定時(shí)很隨意,綁定后很專一
  • 服務(wù)端 TCP 進(jìn)程通過 SO_REUSEADDR 可以玩出高可用的花樣
  • 服務(wù)端 UDP 進(jìn)程用 SO_REUSEPORT 能實(shí)現(xiàn)真正的端口共享和負(fù)載均衡

掌握這些,你已經(jīng)超越大多數(shù)面試者了。因?yàn)槟悴恢恢?是什么",還懂"為什么"和"怎么用"。

下次面試遇到這題,可以先給出簡答,然后補(bǔ)充:"這個(gè)問題其實(shí)很有深度,我可以從幾個(gè)角度分析一下..."——面試官一定會(huì)眼前一亮!

責(zé)任編輯:趙寧寧 來源: 跟著小康學(xué)編程
相關(guān)推薦

2022-07-26 00:00:02

TCPUDPMAC

2024-03-05 10:07:22

TCPUDP協(xié)議

2024-03-18 08:21:06

TCPUDP協(xié)議

2019-08-20 10:24:39

HTTPSSSHLinux

2016-12-15 08:54:52

線程sessionopenSession

2024-04-28 18:31:03

2021-08-16 20:48:34

嵌入式單片機(jī)信息

2009-06-09 12:38:12

NetBeanseclipse

2021-01-18 06:18:25

監(jiān)聽端口數(shù)組

2024-09-05 16:01:55

2020-03-03 17:47:07

UDP TCP面試題

2013-10-17 10:35:06

TCP字節(jié)流UDP數(shù)據(jù)報(bào)

2015-05-12 10:26:56

iptraf運(yùn)維工具

2016-12-20 13:55:52

2019-05-22 09:28:21

TCPUDP端口號(hào)

2018-05-09 15:57:19

2023-07-11 09:26:32

2022-08-11 16:01:26

勒索軟件網(wǎng)絡(luò)攻擊

2020-11-10 07:13:44

端口號(hào)進(jìn)程

2024-01-19 22:02:29

Storage封裝
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)