传输层解决两件事:交给哪个程序(端口),要不要保证可靠(TCP/UDP)。 TCP 与 UDP 的端口是两套独立的编号空间,同一个数字可以各用一份。
2.4.4 讲的是「送到哪台机器」,这一节讲「交给哪个程序」。 这一节会真绑一次同端口,验证两套编号空间。
一、两个问题,一个层解决
传输层的两个职责:
| 职责 | 怎么做 | 不做的后果 |
|---|---|---|
| 区分程序 | 端口号 | 多个程序没法共用一条链路 |
| 决定可靠性 | 选 TCP 或 UDP | 要么都付代价、要么都不保证 |
第一行是「多任务」的基础:一台机器同时跑浏览器、下载器、邮件客户端, 进来的包怎么知道给谁?靠端口号。 没有端口,一台机器就只能跑一个联网程序。 第二行是「选择」的价值: 可靠与低延迟是矛盾的——要保证不丢,就得等确认、就得重传,延迟必然上去。 所以必须让应用自己选。 这就是为什么同一层有两个协议,而不是一个「最好的」。
二、两套独立的端口空间
同一个数字,TCP 和 UDP 各有一份:
| 协议 | 端口范围 | 典型用途 | |---|---| | TCP | 0~65535 | 网页、文件、邮件 | | UDP | 0~65535(独立) | DNS、视频、游戏 |
第二行那个「独立」是本节的重点:你可以在同一个端口号上同时监听 TCP 和 UDP, 两者互不冲突。 DNS 就是典型例子:53 号端口 TCP 与 UDP 都在用,UDP 走普通查询、TCP 走大应答与区域传送。 这个设计的好处是「端口号够用」:16 位只有 65536 个号, 如果 TCP 与 UDP 共用一套,很快就分完了。 顺带说一句端口的三个区间:0~1023 是「知名端口」(要权限),1024~49151 是「注册端口」, 49152~65535 是「临时端口」(系统随机分配)。 你写客户端时用的那个端口,就在最后一段里。
三、完整的目的地
「送到哪」需要三样东西一起:
| 组成 | 决定什么 | 例子 |
|---|---|---|
| IP 地址 | 哪台机器 | 192.168.3.152 |
| 端口号 | 哪个程序 | 443 |
| 协议 | TCP 还是 UDP | tcp |
三者缺一不可:只有 IP 加端口,不知道是 TCP 还是 UDP; 只有 IP 加协议,不知道给哪个程序。 所以「五元组」这个概念里,是把「源 IP、源端口、目的 IP、目的端口、协议」全列上—— 它是「一条连接」的唯一标识。 这也是防火墙规则的基本单位:「允许 192.168.3.0/24 访问 10.0.0.1 的 443 端口 TCP」, 这句话里三样东西都用上了。 少写一样,规则的范围就变了。 最后一个容易忽略的点:端口号只在主机内部有意义,出了网卡就没人看了。 所以不同机器的同一个端口号不冲突。
四、动手 Demo:同一个端口号,TCP 与 UDP 可以同时用
先让 TCP 绑一个端口,再让 UDP 绑同一个。 能成功,就证明这是两套独立的编号空间。
import socket
t = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
t.bind(('127.0.0.1', 0))
t.listen(1)
port = t.getsockname()[1]
print('TCP 绑到 %d' % port)
try:
u = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
u.bind(('127.0.0.1', port))
u.close()
print('UDP 绑同一个端口:成功')
except OSError as e:
print('UDP 绑同一个端口:失败(%s)' % e.strerror)
t.close()
实跑输出:
--------------------------------------------------------------------
同一个端口号,TCP 与 UDP 可以同时用
--------------------------------------------------------------------
**传输层的「端口」是两套独立的编号空间。**下面真绑一次,看能不能共存。
**TCP 先绑到 54966 号端口。**
**UDP 再绑同一个 54966 号端口:成功**
**成功了,说明 TCP 与 UDP 的端口是两套独立的编号**:
**同一个数字,一个给 TCP 用、一个给 UDP 用,互不冲突。**
**DNS 就是典型例子:53 号端口 TCP 与 UDP 都在用**,**UDP 走普通查询、TCP 走大应答与区域传送。**
**这也是「传输层」这一层存在的意义**:**IP 只把包送到机器,端口才决定交给哪个程序、走哪个协议。**
**所以「IP 地址 + 端口 + 协议」才是完整的目的地**,**少一样都可能送错。**
两次绑定都成功:说明 TCP 与 UDP 的端口是两套独立的编号,
同一个数字,一个给 TCP 用、一个给 UDP 用,互不冲突。
这个端口号每次运行都不一样:因为绑的是 0,系统会从临时端口区间里随机挑一个。
所以别把某个具体数字当成固定值记。
注意这里绑的是 127.0.0.1:只在本机可用,外部连不进来。
如果要对外提供服务,得绑 0.0.0.0(所有网卡)。
这个区别在写服务端时最容易搞错——绑了 127.0.0.1 然后抱怨「别人连不上」,是很常见的坑。
30 秒实验
- 把 UDP 那次也改成监听 0 端口,看两者会不会撞。
- 试着绑 80 端口(知名端口),看成功还是报权限。
- 想一下:为什么临时端口从 49152 开始,不从 1024 开始?
常见误区
- 以为 TCP 与 UDP 共用一套端口。 两套独立,同一个数字可以各用一份。
- 以为端口号能跨机器标识程序。 它只在主机内部有意义,出了网卡就没人看。
- 以为「IP 加端口」就是完整目的地。 还要有协议,否则不知道是 TCP 还是 UDP。
自测三问(点开对答案)
1. 传输层解决哪两个问题? —— **区分程序(端口号)与决定可靠性(选 TCP 或 UDP)。**没有端口,一台机器只能跑一个联网程序。 2. 为什么 TCP 与 UDP 的端口是两套独立编号? —— **16 位只有 65536 个号**,共用一套很快会分完。 独立之后,同一个数字可以各用一份(如 DNS 的 53)。 3. 「完整的目的地」由哪三样组成? —— **IP 地址(哪台机器)、端口号(哪个程序)、协议(TCP 还是 UDP)。**三者缺一不可。下一节讲最上面那一层:应用层。
- ☐ (本节完,下一节 2.4.6 应用层(会话层以上的分层))