網路與 IP

TCP 連接埠號和 UDP 連接埠號的區別:同一個連接埠能否同時使用

TCP 連接埠號和 UDP 連接埠號是兩套互不相干的編號空間,各有 0–65535。系統先按 IP 首部的協議號分出 TCP 和 UDP,再到各自的連接埠表裡找程式,所以 TCP 53 和 UDP 53 可以同時被佔用、互不衝突。也正因為是兩套編號,放行連接埠時必須寫明協議,只開了 TCP 53 的 DNS 伺服器,絕大多數查詢照樣進不來。

作者 頂聯產品團隊發布於 6 分鐘閱讀

TCP 連接埠號和 UDP 連接埠號的區別,一句話說完:它們是兩套互相獨立的編號,各自從 0 到 65535。一個包到達伺服器,核心先看 IP 首部裡的協議號,6 交給 TCP,17 交給 UDP,然後才在對應協議的連接埠表裡查詢是哪個程式在等這個包。所以 TCP 的 53 號和 UDP 的 53 號是兩個不同的連接埠,可以同時被兩個程式佔用,也可以由同一個程式分別佔用。DNS 就是這樣用的:UDP 53 處理普通查詢,TCP 53 處理大應答和區域傳送。反過來,這也意味著防火牆、安全組放行時必須寫明協議,查監聽連接埠時要用 ss -tulnp 把兩類都列出來。

TCP 連接埠和 UDP 連接埠為什麼不衝突

連接埠號寫在傳輸層首部裡,而決定用哪個傳輸層協議解析的,是更外層 IP 首部裡的協議號。核心收包的順序是:

步驟 看哪個欄位 例子
1 IP 首部的目的位址:是不是發給本機的 203.0.113.53
2 IP 首部的協議號(8 位):交給哪個協議模組 6 是 TCP,17 是 UDP,132 是 SCTP
3 傳輸層首部的目的連接埠(16 位):在該協議的連接埠表裡查詢 53
4 找到對應的套接字,把資料交給持有它的程式 named、unbound 等 DNS 服務

第 2 步已經把 TCP 和 UDP 分開了,第 3 步只在各自的表裡查,兩張表互不相干。可以把它理解為兩棟樓裡的門牌號:A 棟 53 號和 B 棟 53 號是兩戶人家。由此可以推出幾條常被問到的結論:

  • TCP 和 UDP 連接埠可以相同。同一台機器上 TCP 53 和 UDP 53 同時監聽,不會報衝突。
  • “連接埠被佔用”只發生在同一個協議內。TCP 8080 被佔了,UDP 8080 照樣能用;Address already in use 報的都是同一協議內的衝突。
  • 兩套編號的數量互不影響。TCP 用掉多少連接埠,與 UDP 還剩多少無關,各自都是 65536 個。
  • 測試方法不能混用。telnet、nc -z 測的是 TCP 握手,測通了只能說明 TCP 連接埠通,不能說明同號的 UDP 連接埠也通。

動手驗證:同一個連接埠號同時監聽 TCP 和 UDP

在一台 Linux 上開三個終端,用 nc 分別在 TCP 和 UDP 的 9000 連接埠上監聽(以 Debian、Ubuntu 的 netcat-openbsd 為例;RHEL 系裝的是 ncat,把 nc 換成 ncat,引數相同):

# 終端 1:TCP 9000
nc -lk 9000
# 終端 2:UDP 9000
nc -lu 9000
# 終端 3:檢視 9000 連接埠上的監聽
ss -tulnp 'sport = :9000'

終端 3 會看到兩行,協議列不同,連接埠相同(範例輸出):

Netid State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp   UNCONN 0      0            0.0.0.0:9000      0.0.0.0:*     users:(("nc",pid=4122,fd=3))
tcp   LISTEN 0      1            0.0.0.0:9000      0.0.0.0:*     users:(("nc",pid=4107,fd=3))

這時讓第二個程式再去繫結 TCP 9000,就會失敗。用 Python 試最直觀:python3 -c 'import socket; socket.socket().bind(("0.0.0.0", 9000))' 會報 OSError: [Errno 98] Address already in use,而 UDP 9000 上的 nc 絲毫不受影響。沒裝 nc 時,同樣用 Python 一行就能驗證“一個程式同時佔用兩個同號連接埠”:

python3 -c 'import socket,time; t=socket.socket(); t.bind(("0.0.0.0",9000)); t.listen(); u=socket.socket(type=socket.SOCK_DGRAM); u.bind(("0.0.0.0",9000)); print("TCP 和 UDP 的 9000 都已繫結"); time.sleep(60)'

53 連接埠是 TCP 還是 UDP:DNS 兩個都用

DNS 是“同一個連接埠號、兩種協議都要用”的典型,各自分工明確:

場景 協議 說明
普通查詢,應答較小 UDP 53 一問一答,不用握手,絕大多數查詢走這裡
應答超過 UDP 能承載的大小 先 UDP,再改 TCP 53 伺服器回一個置上 TC(截斷)標誌的應答,客戶端看到後用 TCP 重新查詢
區域傳送(AXFR;IXFR 通常也走 TCP) TCP 53 主從 DNS 伺服器之間同步整個區的記錄
DNS over TLS TCP 853 加密 DNS,連接埠不同
DNS over QUIC UDP 853 同樣是 853,換成 UDP

UDP 能承載多大的應答,經歷過幾次變化:最早的 RFC 1035 把 UDP 上的 DNS 報文限制在 512 位元組;EDNS(0)(RFC 6891)允許客戶端在查詢裡宣告自己能接收更大的 UDP 報文;2020 年的 DNS Flag Day 建議把這個值設為 1232 位元組,以避開 IP 分片。超過宣告大小的應答,就要截斷後改走 TCP。RFC 7766 進一步要求所有通用的 DNS 實現都必須同時支援 UDP 和 TCP,TCP 不再是可有可無的備用通道。

用 dig 可以親眼看到切換過程。關閉 EDNS、要求 dig 遇到截斷不要自動重試,應答一旦超過 512 位元組,返回的頭部標誌裡就會出現 tc(把 example.com 換成一個 TXT 記錄較多、應答超過 512 位元組的域名):

# 只用 UDP、不帶 EDNS,並忽略截斷:大應答會顯示 flags: qr tc ...
dig @203.0.113.53 example.com TXT +noedns +ignore
# 去掉 +ignore,dig 會提示 ;; Truncated, retrying in TCP mode. 然後改用 TCP 重查
dig @203.0.113.53 example.com TXT +noedns
# 直接用 TCP 查詢,驗證 TCP 53 是否放行
dig @203.0.113.53 example.com +tcp

這套機制對放行規則的要求很直接。自己執行權威 DNS 的伺服器,入方向要同時放行 UDP 53 和 TCP 53:區裡簽了 DNSSEC、某個名字下掛著很多 A 記錄或很長的 TXT 記錄時,應答很容易超過 1232 位元組,只開 UDP 的話,這部分查詢會在截斷之後失敗,而且只有特定域名、特定解析器出問題,很難一眼看出原因。主從同步也走 TCP:從伺服器主動連線主伺服器的 TCP 53 拉取區資料,主伺服器只放行 UDP 的話,從伺服器永遠同步不到。

同一個號碼,在 TCP 和 UDP 上不一定是同一個服務

IANA 給大多數知名服務分配連接埠時,會把 TCP 和 UDP 的同號一起登記給它,哪怕實際只用其中一種;但也有少數號碼,TCP 和 UDP 登記的是完全不同的服務。下表按“同號連接埠在兩種協議上分別是什麼”整理,放行時據此決定開哪一邊:

連接埠 TCP 上 UDP 上 放行建議
22 SSH IANA 也登記給 SSH,實際不用 只放 TCP
53 DNS 大應答、區域傳送 DNS 普通查詢 權威 DNS 兩邊都放
80 HTTP 登記了,實際沒有服務使用 只放 TCP
88 Kerberos,報文較大時 Kerberos 域控兩邊都放
123 登記了,實際不用 NTP 只放 UDP
389 LDAP CLDAP,Active Directory 定位域控時使用 域控兩邊都放
443 HTTPS(HTTP/1.1、HTTP/2) HTTP/3(QUIC) 啟用了 HTTP/3 才放 UDP
512 exec(rexec) biff(comsat) 兩個不同的老服務,都不應對外開放
513 login(rlogin) who(rwhod) 同上
514 shell(rsh) syslog 收日誌一般只放 UDP;rsyslog 走 TCP 時習慣上也用 514
520 efs RIP 路由協議 按實際用途放行
3389 RDP 會話 RDP 8.0 起的 UDP 傳輸 對外開 RDP 時兩邊都放,網路較差時更流暢
5060 SIP SIP 兩邊都放;SIP over TLS 用 TCP 5061

512–514、520 這幾個號碼說明了一個事實:只說“開 514 連接埠”,可能被理解成開 rsh,也可能是收 syslog,工單裡必須寫清協議。本機的服務名資料庫裡能直接查到這種差別:

getent services 514/tcp     # 輸出 shell  514/tcp  cmd
getent services 514/udp     # 輸出 syslog  514/udp

防火牆、安全組放行:協議必須寫清楚

幾乎所有防火牆規則都把“協議 + 連接埠”作為一個整體來匹配。以一台權威 DNS 伺服器 203.0.113.53 為例,各種工具的寫法如下。

iptables 和 nftables:

# iptables:--dport 必須跟在 -p tcp 或 -p udp 後面,不寫協議會報 unknown option "--dport"
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j ACCEPT
# nftables:一條規則同時匹配兩種協議
nft add rule inet filter input meta l4proto { tcp, udp } th dport 53 accept

firewalld 和 ufw:

# firewalld:兩個連接埠分別寫協議;預定義的 dns 服務已經包含 53/tcp 和 53/udp
firewall-cmd --permanent --add-port=53/tcp --add-port=53/udp && firewall-cmd --reload
firewall-cmd --permanent --add-service=dns && firewall-cmd --reload
# ufw:寫協議只放一種,不寫協議則 TCP、UDP 一起放行
ufw allow 53/udp
ufw allow 53

ufw 的“不寫協議就兩種都放”很方便,也容易放多了:ufw allow 3306 會順帶放行 UDP 3306,雖然 MySQL 並不監聽它,但規則比實際需要寬。能寫協議的時候就寫上。

Windows 防火牆每條規則只能選一種協議,TCP、UDP 各建一條:

New-NetFirewallRule -DisplayName "DNS UDP 53" -Direction Inbound -Protocol UDP -LocalPort 53 -Action Allow
New-NetFirewallRule -DisplayName "DNS TCP 53" -Direction Inbound -Protocol TCP -LocalPort 53 -Action Allow

託管機房沒有安全組,靠邊界交換器或路由器的 ACL 放行時,同樣是兩條規則。華為和思科的寫法:

# 華為高階 ACL
acl number 3001
 rule 5 permit udp destination 203.0.113.53 0 destination-port eq 53
 rule 10 permit tcp destination 203.0.113.53 0 destination-port eq 53
# 思科擴充套件 ACL
ip access-list extended DNS-IN
 permit udp any host 203.0.113.53 eq 53
 permit tcp any host 203.0.113.53 eq 53

雲平台的安全組也是同樣的邏輯:規則裡的協議一欄要麼選 TCP,要麼選 UDP,同一個連接埠兩種都要時就建兩條。不要圖省事選“全部協議”,那會把這個來源對這台伺服器的所有連接埠一起開啟。

用 ss -tulnp 同時檢視 TCP 和 UDP 監聽連接埠

ss -tulnp 是排查連接埠問題的第一條命令,五個引數各管一件事:-t 列 TCP,-u 列 UDP,-l 只看監聽中的,-n 連接埠顯示數字不轉換成服務名,-p 顯示佔用連接埠的程序(需要 root)。一台跑著 DNS 服務的機器,輸出類似這樣(範例):

Netid State  Recv-Q Send-Q    Local Address:Port  Peer Address:Port Process
udp   UNCONN 0      0             127.0.0.1:323        0.0.0.0:*     users:(("chronyd",pid=702,fd=5))
udp   UNCONN 0      0          203.0.113.53:53         0.0.0.0:*     users:(("named",pid=1180,fd=512))
tcp   LISTEN 0      10         203.0.113.53:53         0.0.0.0:*     users:(("named",pid=1180,fd=514))
tcp   LISTEN 0      128             0.0.0.0:22         0.0.0.0:*     users:(("sshd",pid=905,fd=3))

讀法要點:

  • 第一列 Netid 就是協議。53 連接埠出現了兩次,一次 udp、一次 tcp,同屬 named 這一個程序,正是“同號連接埠兩種協議都用”。
  • UDP 的狀態是 UNCONN,不是 LISTEN。UDP 沒有連線,只要繫結了連接埠就算在“監聽”。不加 -l、用 ss -uan 檢視時,偶爾會看到狀態為 ESTAB 的 UDP 行,那是程式對 UDP 套接字呼叫了 connect,固定了對端位址,並不代表建立了連線。
  • 位址決定誰能存取。chronyd 的 UDP 323 只綁在 127.0.0.1,只給本機的 chronyc 用,防火牆放不放行都不影響;named 綁在 203.0.113.53,外部能否存取取決於防火牆。

幾個常用的變體:

ss -ulnp                     # 只看 UDP
ss -tlnp                     # 只看 TCP
ss -tulnp 'sport = :53'      # 只看 53 連接埠,兩種協議都列出
lsof -nP -i :53              # 用 lsof 查,同樣會列出 TCP 和 UDP

Windows 上 TCP 和 UDP 要分開查:

Get-NetTCPConnection -LocalPort 53 -State Listen
Get-NetUDPEndpoint -LocalPort 53
netstat -ano -p UDP | findstr :53

netstat -ano 其實同時列出 TCP 和 UDP,但 UDP 端點沒有狀態,習慣用 findstr LISTENING 過濾的話,UDP 連接埠會被全部漏掉。排查“連接埠開了卻連不上”時,先用這些命令確認服務實際監聽的是哪種協議、哪個位址,再去對照防火牆規則,能省掉大半時間。

在機房裡怎麼落地

託管和獨立伺服器多數沒有云平台那樣的安全組,連接埠放行落在兩處:伺服器自己的防火牆,以及機房邊界裝置上的 ACL。邊界 ACL 按協議寫規則,改動頻繁時最怕“誰加了一條 permit ip any”說不清。Toplink DCIM 的交換器管理支援在瀏覽器裡開啟交換器的 SSH 終端,會話全程錄影並記錄命令級日誌,每條 ACL 規則的增刪都能追溯到人和時間。伺服器側防火牆規則寫錯、把 SSH 的 TCP 22 也擋在外面時,客戶可以在客戶自助端開啟 VNC 控制檯登入系統,自己改回規則,不必提工單等工程師進機房。

常見問題

HTTPS 的 TCP 443 和 HTTP/3 的 UDP 443 會衝突嗎?

不會,它們是兩個連接埠。Nginx 1.25 起支援 HTTP/3,可以在同一個 server 塊裡同時寫 listen 443 ssl; 和 listen 443 quic reuseport;,前者監聽 TCP 443,後者監聽 UDP 443。回應頭裡還要加 Alt-Svc 告訴瀏覽器可以用 HTTP/3,防火牆和安全組也要另外放行 UDP 443,否則瀏覽器會退回 TCP 上的 HTTP/2 或 HTTP/1.1,網站照樣能開啟,只是沒用上 HTTP/3。

IPv4 和 IPv6 的同一個連接埠算一個嗎?

要看程式怎麼監聽。Linux 預設 net.ipv6.bindv6only 為 0,監聽 [::]:80 的 IPv6 套接字會同時接收 IPv4 連線,此時再單獨監聽 0.0.0.0:80 會報位址已被佔用;程式給套接字設定了 IPV6_V6ONLY 後,兩者才能分別監聽。Nginx 的 listen [::]:80 預設就是隻收 IPv6,所以要和 listen 80 一起寫。

除了 TCP 和 UDP,還有別的協議有連接埠嗎?

有。SCTP(IP 協議號 132)也有自己獨立的 16 位連接埠,常見於電信信令網,IDC 業務很少遇到;放行時要在防火牆裡選 SCTP 協議。ICMP 沒有連接埠,ping 走的就是 ICMP,所以 ping 得通和連接埠通不通沒有關係。

想看看在你的機房裡怎麼用?

從一次產品示範開始,梳理你的業務鏈路。

查看價格
服務熱線 400-112-2951

讓我們聊聊你的 IDC 業務

掃碼新增企業微信,預約產品示範或申請試用。

Toplink 企業微信二維碼

長按儲存或使用企業微信 / 微信掃描

也可致電
400-112-2951
Telegram
@TopLink88