理解端口号
理解端口号
什么是端口号?
在网络通信中,我们都是类似于通过构建一条通信通道来实现信息的传输。要建立这样一条通道,就需要唯一确定信息的发送者和信息的接收者。IP 地址可以用于在网络中唯一标识一台设备,比如101.22.xxx.xx
。我们通过发送方和接收方的 IP 地址,就可以实现两台计算机之间的数据包的收发。然而,在同一台计算机上,可能运行着多个网络程序,比如浏览器、邮件客户端、数据库服务器等等,仅靠 IP 地址将数据包发送到了目标计算机后,还无法确定到底应该是哪个程序要接收数据。比如我们一边在 SSH 远程登陆服务器,一边下载邮件,仅靠 IP 地址系统也没有办法区分 SSH 和邮件数据。
为了解决这个问题,人类引入了端口号的概念,作为 IP 地址的扩展信息以唯一标识同一台计算机上的不同网络应用程序。比如在101.22.xxx.xx:8080
中,8080就是端口号。这样,通过 IP 地址+端口号组合,就可以唯一将数据包发送给相应的应用程序。实际上在互联网通信协议中(TCP/IP),通过5个参数就可以完全地确定一条通信通道:
1 | (源 IP,目标 IP,源端口,目标端口,协议号) |
- 源 IP 就是通信的发送方 IP,比如我们的电脑
192.168.1.100
。 - 目标 IP 就是通信的接收方 IP,比如远程网站
93.184.216.34
。 - 源端口就是发送方端口,如
52345
。 - 目标端口就是远程服务器监听接收信息的端口,比如
443
。 - 协议号指代所采用的通信协议,其中 TCP 的协议号为 6,UDP 的协议号为 17。
这里的 TCP 和 UDP 都是传输层的协议,他们类似于同一目标——在网络上发送数据的不同实现方法,由于侧重点不同所以采取了不同的方案。TCP 的目标是可靠传输数据,确保数据不丢失、不乱序,因此有三次握手等的严格确认机制,需要建立 TCP 连接才能发送数据。文件传输、网页加载等对可靠性要求高的场合一般会采用 TCP 协议。而 UDP 的目标是快速传输数据,没有严格控制机制,也无需提前建立链接,丢包乱序都无所谓。在实时性要求高的场合,比如视频直播和游戏会采用 UDP 协议。一般情况下,我们使用的主要都是 TCP 协议。

上面是一些典型的互联网协议,其中 TCP 和 UDP 属于传输层,负责如何可靠地传输数据,它们不关心传输的内容是什么。HTTP/SMTP/FTP 这些属于应用层,定义具体的数据如何被解析和使用(邮件、远程登陆、网页等),而它们不关注数据如何传输。上面的图里除了 TCP 和 UDP,剩下的协议都属于应用层,都是建立在 TCP 之上的。
协议 | 作用 | 默认端口 |
---|---|---|
WebSocket | 长连接、全双工通信 | 80(ws://),443(wss://) |
HTTP | 网页数据传输(明文) | 80 |
HTTPS | 加密网页数据传输(基于 TLS/SSL) | 443 |
SMTP | 发送邮件 | 25, 587 |
FTP | 文件传输 | 21, 20 |
WebSocket、HTTP、HTTPS、SMTP、FTP 都属于应用层协议,它们依赖传输层协议(TCP)来进行数据传输,定义了如何解析和使用数据。应用层协议是"数据的格式和解析",传输层(TCP/UDP)是"数据如何可靠/快速传输"。
如何确定端口号?
在建立一条通信通道时,我们需要发送方的端口号和接收方的端口号。接收方一般都是服务器,服务器监听某个固定端口,执行相应的操作。接收方的端口号可以分成两类。第一类是保留端口(0-1023),这些端口通常都是由操作系统和标准协议使用的,每一个端口号都唯一确定一个服务。这些由 IANA(互联网号码分配局)统一管理,普通用户无法使用这些端口。访问指定端口时,必须遵循该端口对应协议的规则,就像调用 API 必须遵循 API 规范一样。比如对于 HTTPS 的 443 端口,客户端发送请求时连接就会自动使用 TLS 加密,发送的方式和 HTTP 的 80 端口一样,不需要我们手动处理;而对于邮件发送的 SMTP 协议的 587 端口,就需要客户端手动启动 starttls()
来切换到 TLS 模式。总的来说,访问指定端口时,必须按照该端口的协议规则进行通信,否则连接会失败,就像 Flask API 需要按照定义的接口调用一样。
协议 | 端口号 | 说明 | 部分连接规则 |
---|---|---|---|
HTTP | 80 | 网页服务(非加密) | 直接发送明文 HTTP 请求 |
HTTPS | 443 | 加密网页服务(SSL/TLS) | 必须使用 TLS 加密 |
FTP | 21 | 文件传输协议 | 需使用 FTP 协议(可能有明文或加密模式) |
SSH | 22 | 远程登录 | 必须使用 SSH 协议(加密认证) |
SMTP | 25 | 邮件服务器之间传输 | 可能明文,可能 starttls() |
SMTP | 587 | 现代邮件客户端发送 | 需 starttls() 切换到加密 |
DNS | 53 | 域名解析 | UDP 默认查询,TCP 处理大数据或 DNSSEC |
第二类是用户端口(1024-49151),这些端口可以自由使用,但有些端口是流行应用的默认端口:
端口号 | 常见应用 |
---|---|
8000 | Django 开发服务器 |
8080 | 常用于 HTTP 备用端口 |
8888 | Jupyter Notebook |
3306 | MySQL 数据库 |
5432 | PostgreSQL 数据库 |
我们自己启动一个服务的时候,比如启动一个 Flask 应用,我们可以让服务自由监听某个空闲端口:
1 | from flask import Flask |
当客户端向 5000 端口发送请求时,就会连接到这个端口,然后服务器输出 Hello, Flask!
。
一般来说,只有在监听端口时,才需要手动指定端口号,而发送数据时,端口号通常是由操作系统动态分配的,不需要手动设置。动态端口的范围是(49152-65535),比如当浏览器访问 https://example.com
时,系统会自动选择一个未使用的端口:
1 | (本地 IP, 52345) → (example.com, 443) |
这种动态分配使得计算机同时运行多个客户端的时候,不会和已有的连接冲突,我们才能无痛地同时访问多个网页或者执行多项互联网操作。
1 | (192.168.1.100, 52345) → (smtp.example.com, 25) # 发送邮件 |
邮件发送的小例子
以邮件客户端的配置为例再巩固一下接口的相关知识。邮件的发送和接收是两个独立的过程,因此在邮件客户端中需要分别配置。在邮件的收发过程中存在两个服务器,一个是邮件发送服务器,一个是邮件接收服务器。A 向 B 发送一个邮件,实际上的流程是 A 先和邮件发送服务器建立链接,将邮件发送到发送服务器上。发送服务器再将邮件转发到接收服务器。之后,B 和邮件接收服务器建立连接,完成邮件的下载。发送邮件的协议一般是 SMTP,接收邮件的协议一般是 IMAP/POP3。整个电子邮件的发送和接收可以整理为:
- 邮件客户端(Outlook、Foxmail、Gmail Web端等)→ 发送邮件 → SMTP 服务器
- SMTP 服务器 → 通过 SMTP 转发邮件 → 收件人邮件服务器
- 收件人邮件客户端 → 连接 IMAP/POP3 服务器 → 下载邮件
SMTP(Simple Mail Transfer Protocol,简单邮件传输协议) 的工作流程如下:
- 邮件客户端(Outlook/Foxmail/Gmail)建立 TCP 连接到邮件服务器(如
smtp.example.com
)。 - SMTP 服务器验证身份(用户名/密码 或 OAuth)。
- SMTP 服务器接收邮件,然后寻找收件人的邮件服务器(如
gmail.com
)。 - SMTP 服务器通过 SMTP 转发邮件到目标服务器(如
smtp.gmail.com
)。 - 收件人的邮件服务器存储邮件,等待收件人下载。
1 | (本地 IP, 52345) → (smtp.example.com, 587) # 发送邮件(加密) |
SMTP 服务器支持多个端口,不同端口的用途和加密方式有所区别:
端口 | 用途 | 是否加密 | 加密方式 |
---|---|---|---|
25 | 服务器之间的邮件转发(MTA-MTA) | ❌ 可选 | 明文或 STARTTLS(部分支持) |
465 | 客户端提交邮件(已废弃的 SMTPS) | ✅ 必须 | SSL/TLS(直接加密) |
587 | 客户端提交邮件(现代推荐) | ✅ 可选 | STARTTLS(明文 + TLS) |
SMTPS 不是一个新的协议,而是一种加密方式。它在 SSL/TLS 加密的 TCP 连接上直接运行 SMTP,即连接建立时就开启加密。类似 HTTPS(HTTP over SSL/TLS)这种方式要求所有 SMTP 服务器都支持 SMTPS,否则无法通信。而STARTTLS 不是一种独立的协议,而是 SMTP 标准中的一个扩展指令,用于在明文连接上动态启用 TLS 加密。SMTP 连接最初是明文的,但客户端可以发送 STARTTLS
指令,要求服务器切换到 TLS 加密模式。其兼容性更强,可以在支持和不支持加密的服务器之间灵活切换。SMTPS(465)类似于打电话前就先打开了 "加密模式"(TLS 连接先建立)。STARTTLS(587)则是先拨号,然后告诉对方 "我们加密对话吧"(明文连接后再切换 TLS)。对于用户来说,发送邮件到中转服务器的 465 或 587 端口没有区别,邮件客户端会自动处理连接方式。但是对于开发者来说,对不同的端口需要采用不同的连接方式。如果连接或者加密方式不正确,服务器就会拒绝请求。
SMTP 只负责发送邮件,但收件人通过 IMAP 和 POP3 协议完成邮件的接收。IMAP(Internet Message Access Protocol)允许多设备同步邮件(邮件存储在服务器上,不删除),适用于多设备办公(如手机、电脑同时收邮件),使用端口 143
(明文)或 993
(SSL/TLS 加密)。OP3(Post Office Protocol 3)的邮件下载到本地后,服务器上的邮件通常被删除,适用于单台设备管理邮件(比如只在一台电脑上收邮件),使用端口 110
(明文)或 995
(SSL/TLS 加密)。
1 | (本地 IP, 52347) → (imap.example.com, 993) # 加密邮件接收 |
端口安全
如果端口直接暴露在公网上,没有任何保护机制,那么就存在安全风险,这个暴露的端口就像围起来的城墙中出现的一个小洞一样。比如最近国家网络安全通报中心提到的,Ollama在本地部署大模型时,会在本地启动一个 Web 服务,默认开放 11434 端口且无任何鉴权机制。攻击者可以直接通过这个端口调用 AI 模型服务,窃取计算资源。而且可以获取已部署模型的相关信息,如 License、训练数据等。如果通过该端口删除或者上传恶意文件等,可以直接导致 AI 模型不可用。有很多种方式进行端口的安全管理,一个简单的方式就是使用 API Key,让只有拥有 API Key 的用户才有权限访问 API,大模型也官方采用了这种方式来进行身份认证。API Key 的基本使用方式就是在请求头部中加入一个 Authorization: Bearer <API_KEY>
字段,服务器验证后才会执行请求返回数据,API Key 还可以设置权限,调用频率等等。
1 | # 使用 API Key 调用大模型 |
在 Flask 应用里,我们同样可以进行 API Key 以及调用频率和权限控制的设置:
1 | from flask import Flask, request, jsonify |
比如在这里,使用 user-key
可以正常访问 /protected
:
1 | curl -H "X-API-KEY: user-key" http://127.0.0.1:5000/protected |
返回
1 | {"message": "Welcome!", "role": "user"} |
而访问 /admin
(仅 Admin 可用),
1 | curl -H "X-API-KEY: user-key" http://127.0.0.1:5000/admin |
就会返回无权限:
1 | {"error": "Forbidden"} |
对于超出访问频率时,HTTP 返回码就会得到 429(Too Many Requests)。
