04.02 地址、名称与路由入口:找到教学 IM 服务的正确层次
返回第四卷 · 前置:04.01 应用通信 · IM 学习路线
04.02 地址、名称与路由入口:找到教学 IM 服务的正确层次
DeepTutor 原稿经技术与教学审阅后的静态课程。域名、IP、端口、路由表和响应都是纸上例子;本次没有运行 Go、DNS 查询、连接命令、站点构建或 IM 服务。
从“服务在哪里”开始
04.01 已画出未来教学 IM 的 u-a(A) → 服务 → u-b(B) 概念路径。若客户端要请求历史,光知道 u-b、c-a 或消息 m-a 仍无法找到服务进程;它还要得到网络位置,并在那个位置找到提供此服务的入口。这里从零区分名字、IP 地址、端口、socket、路由,最后练习把不同失败定位到正确阶段。04.03 才讲 HTTP 与 WebSocket 的具体请求和握手。
当前课程项目仍是本地 imhistory check/list/export,没有启动或验证在线服务。本章所有网络身份与地址都是虚构教学数据。使用 192.0.2.0/24、198.51.100.0/24 和 2001:db8::/32 等 RFC 保留的文档地址,绝不把它们当作当前机器的真实网络配置;虚构域名 chat.example.test 也不声称在公共 DNS 中有真实记录。
| 起步 | 原理 | 业务迁移 |
|---|---|---|
| 名字、IP、端口、socket 各回答什么 | 前缀、路由、DNS 与连接的先后 | 区分解析、连接与历史查询失败 |
一、先给五种“标识”安排正确的工作
用户问“u-b 的历史在哪”,可能混用五种不同对象:
| 名称 | 本题例子 | 主要回答什么 | 它不能代替什么 |
|---|---|---|---|
| IM 用户 ID | u-b | 业务上是哪位用户 | 网络主机地址 |
| IM 会话 ID | c-a | 哪组消息的归属 | 服务端口 |
| 域名 | chat.example.test | 人和程序使用的服务名称 | 保证服务正在运行 |
| IP 地址 | 192.0.2.10 | 网络层要把数据送往哪个地址 | 某个应用进程或会话权限 |
| 端口 | 8080 | 某种传输协议下的服务入口编号 | 目标主机是否可达 |
客户端需要把人可读的服务名称或已知地址转成可尝试连接的端点,然后才可能发送应用请求。u-b 与 c-a 会在服务收到请求后参与身份、授权和历史范围判断;它们不是 DNS 要解析的主机名。本节的域名和数字都是纸上标签,不要拿它们去做真实连通性测试。
一个端点可以先粗略写作 192.0.2.10:8080。这表示“希望到这个 IP 的这个端口”,尚未说明采用 TCP 还是 UDP、目标进程是否监听、网络路径是否通、应用协议是否正确。“端点可写出来”远远不等于“历史查询会成功”。
二、IP 地址和前缀:哪些位用于匹配范围
IPv4 地址有 32 位,常写为四段十进制数,例如 192.0.2.10;每段对应 8 位,取值为 0–255。IPv6 地址有 128 位,常用带冒号的十六进制形式并允许规范的零压缩,例如文档地址 2001:db8::10。两者的文本样式不同,但都用于网络层寻址;一个设备可有多个地址,地址还可能随网络条件改变,不能把“设备 A”永久等同某个 IP。04.11 才深入 NAT、局部寻址和转发限制。
前缀用 /位数 表达一组地址共同的高位。IPv4 192.0.2.0/24 表示前 24 位固定:在本题的文字形式中,192.0.2.10 和 192.0.2.20 属于这个范围,198.51.100.20 不属于。/24 不是“24 台主机”,也不是端口号;剩余 8 位可给出 256 种位组合,具体哪些可分配给主机还受网络配置与用途影响,本章不把它们全部称为可用主机。
纸上前缀:192.0.2.0/24
相同的前 24 位:192.0.2.10、192.0.2.20
不同的前 24 位:198.51.100.20
IPv6 文档前缀:2001:db8::/32
示意地址:2001:db8::10这几段地址由 RFC 专供说明文档,不用于实际公网或本地连接实验。这里的“前缀相同”只是一项地址归类判断,不证明两个程序能互访:还可能缺路由、链路、监听、权限或协议,实际互通须在真实、获授权的实验环境分别验证。
三、解析出 IP 后,主机还要选择路由
客户端要把数据发往某个目的 IP,本机网络栈还要决定从哪个接口送出、下一步交给哪个相邻节点。一个入门模型是拿目的 IP 与路由表的前缀比对,优先采用更具体的匹配;若没有更具体项,才可能走默认路由。中间设备也可继续作类似转发决定。DNS 负责名称解析,不替本机路由表自动证明“有一条可走通的路径”。
下面的表完全是纸上假设,不代表任何真实 Linux 机器或可配置的文档网络:
| 目的前缀 | 假想出口 | 含义 |
|---|---|---|
192.0.2.0/24 | 教学链路 A,直接相邻 | 目的地址在这组范围时选它 |
0.0.0.0/0 | 教学下一跳 192.0.2.1 | 没有更具体 IPv4 匹配时的默认选择 |
于是 192.0.2.20 命中 /24;198.51.100.20 不命中 /24,若此表是完整可用路由表,它会选择 /0。/0 匹配所有 IPv4 地址,但“有默认项”仍不等于下一跳真的可达,也不等于终点服务正在监听。若表中没有匹配的可用路由,连接前就可能失败;若路径中某处丢弃或拒绝,观察到的错误又可能不同。具体链路转发、NAT 和路由协议在 04.11 深化。
地址和路由的证据层也要守住:DNS 给出 192.0.2.10,只意味着名称按某次解析结果指向这个地址;路由表选出出口,只意味着本机有发送计划;真正到达目的主机、建立连接、收到 HTTP 响应还要分别观察。不能把四步写成一个“网络已经通了”。
四、端口与 socket:找到网络上的程序入口
同一机器可能同时运行历史查询、诊断和其他服务。IP 只定位网络入口;传输协议再用端口区分要交给哪个服务入口。常见 TCP/UDP 端口编号在 0–65535 范围内,协议类别也是定位的一部分:写出 8080 而不说 TCP 或 UDP,不足以完整表达服务。端口号不是消息 ID,也不表示有权限读 c-a。
在 Linux/Go 中,socket 是程序与网络协议栈交互的接口和资源对象。服务端可先监听一个本地地址与端口;客户端连接时,通常还具有自己的本地地址和临时源端口。一个监听入口能接受来自多个不同客户端的连接,不能以“监听端口只有一个”推出“只能同时接一个客户端”。
纯纸上 TCP 连接一:客户端 192.0.2.20:53124 → 服务 192.0.2.10:8080
纯纸上 TCP 连接二:客户端 192.0.2.21:53125 → 服务 192.0.2.10:8080
服务端监听端点相同;两条连接的客户端一侧不同。这里的源端口只是示意,实际可由系统分配,不能把 53124 当固定值。描述一条 TCP 连接时,要同时考虑两端地址和端口及协议;单个 192.0.2.10:8080 只是目标端点,不是整条连接的唯一身份。03.03 的文件描述符为进程持有的 socket 提供资源入口,但 FD 编号同样不是网络地址。
IPv6 地址含冒号,因此与端口写在一起时需避免歧义:[2001:db8::10]:8080 是常见的 host:port 形式;Go 的 net.JoinHostPort 可帮助构造这种文本。127.0.0.1 指向本机 IPv4 loopback;若教学服务只监听它,其他机器不能仅凭服务进程运行就直接连到该监听入口。监听 0.0.0.0 常表达所有本地 IPv4 地址上的入口,但也不自动意味着公网可达:路由、防火墙、代理和部署网络仍可能限制它。这些地址语义只作知识说明,本章不实际监听端口。
五、DNS 把名称变成候选地址,不把服务变为健康
人更容易记 chat.example.test,而网络发送需要目的地址。DNS 名称解析按名称与记录规则返回地址等信息,例如 IPv4 的 A 记录或 IPv6 的 AAAA 记录。这里的 chat.example.test 是 RFC 保留测试域名中的虚构名称;下表的回答也是教学假设,现实公共 DNS 不保证也不应按它返回。missing.example.invalid 则用来表示有意不可用的示例名称,不能当真实服务访问。
| 纸上查询 | 本题假定的结果 | 该结果能证明什么 |
|---|---|---|
chat.example.test 的 A 记录 | 192.0.2.10 | 名称得到一个文档用 IPv4 候选地址 |
chat.example.test 的 AAAA 记录 | 2001:db8::10 | 名称得到一个文档用 IPv6 候选地址 |
missing.example.invalid | 不得到可用地址 | 不能进入以该名字为目标的连接步骤 |
DNS 系统中可以有缓存、递归查询和权威数据来源。缓存能减少重复解析,但也可能在一段时间内持有旧回答;记录的 TTL 用于规定缓存有效时间等行为。一次解析可能返回多个地址,客户端怎样选择、失败后是否尝试其他地址,取决于调用方与实现。这里不假设“名字永远只对应一个 IP”,也不把同一次观察推广到所有设备和时刻。
域名解析成功只给出可尝试的地址,仍不证明:本机有可用路由、目标端口有人监听、传输连接能建立、对方说的是预期应用协议、c-a 历史存在。若客户端直接使用 IP 字面量,通常无需为该目标名字做这一步 DNS 解析,但后续路由、连接和应用检查仍不可省略。
解析失败也要说清类型:名字不存在、当前解析器没有可用回答、解析请求超时、缓存里有旧信息,给出的观察可能不同。不能看到“连接失败”就先认定 DNS 错,更不能看到 DNS 有结果便认定服务健康。04.12 才用真实环境中的查询与抓包证据做系统排障;本章只是把顺序和证据范围固定。
六、从名称到历史查询结果:哪一步失败了
假想未来教学服务提供一个历史查询入口。客户端先解析 chat.example.test 得到本题设定的 192.0.2.10,选择路由,再尝试 TCP 端口 8080,最后发出类似“查询 c-a 历史”的应用请求。HTTP 方法、路径、状态码和资源表示将在 04.03 正式讲;这里先把 404 当作某个 HTTP 响应者返回的“请求的资源未找到”状态示例,403 当作某个 HTTP 响应者拒绝访问的示例,不能把它们说成所有实现的唯一业务映射。
服务名 → 名称解析 → 候选 IP → 本机路由选择 → 连接目标端口
→ 应用请求 → 某个 HTTP 响应 → 解析业务结果| 观察结果 | 最少说明已走到哪层 | 不能因此得出的结论 |
|---|---|---|
| DNS 没得到可用地址 | 还没形成这次目标连接的目的 IP | 服务端 JSON 拒绝了请求 |
| 连接被拒绝 | 已尝试某个网络目标,连接未按预期建立 | 唯一原因必为“服务未启动” |
| 连接超时 | 期限内没有得到预期连接结果 | 对端一定从未收到请求或永久不可达 |
| 收到 HTTP 404 | 某个 HTTP 响应者处理到了应用请求 | 一定是预期 IM 服务;DNS、端口和路径配置必然都正确 |
| 收到 HTTP 403 | 某个 HTTP 响应者拒绝访问 | Linux 文件权限必然有问题 |
| 收到 HTTP 200 | 某个 HTTP 响应者报告本次请求成功 | u-b 已收到消息或 c-a 历史必然完整 |
“某个 HTTP 响应者”措辞很重要:代理、错误端口上的其他 HTTP 服务或配置错误的目标,也可能返回 404/403/200。看到状态码通常说明这条观察路径不再停留在 DNS 失败,但还要核对实际连接目标、代理、请求路径和响应身份,才能说它来自预期服务。404 与 403 属于应用响应,不能简单归成“IP 不通”;具体服务可能用不同状态表达未授权或资源不存在,应以协议合同为准。
连接被拒绝可能与没有进程监听有关,也可能由网络中间策略主动拒绝;连接超时说明在限定时间内没有得到预期结果,可能涉及路径丢弃、对端无响应或其他条件。两者不是单一根因诊断。若把端口写错,即使域名、IP、路由都正确,也可能连接到错误应用,返回看似正常但语义不对的响应。
七、反例与 Go 网络 API 的学习入口
沿上一节给未来 IM 的历史查询写一份故障记录,应至少标注:目标名称和端口、所用地址族、解析得到的候选地址、选择的连接目标、失败阶段、时间、具体错误类别、实际响应者线索。在公开记录里对真实地址、凭据和用户信息做脱敏。这里的 chat.example.test 和文档 IP 可以直接用于纸上推演,但不能当生产配置或连通性测试目标。
几个反例能检查你的分层判断:
- 错误域名:还未得到候选地址就失败,不能先调服务端 JSON 解析。
- 错误端口:名称和 IP 可正确,仍可能没有监听者或连到另一种应用。
- 只监听 loopback:本机客户端可能连通,另一台机器仅凭相同端口号不能连通。
- 有默认路由:只是本机知道下一跳,远端服务仍可能不可达。
- 返回 404:至少有某个 HTTP 响应者;应检查实际目标与请求资源,而不是再问“DNS 是否完全没解析”。
- 返回 403:应审查应用/代理的访问规则;不能直接修 Linux 文件权限或给进程更高系统权限。
“能 ping 到某个地址”也只能提供特定网络探测范围内的线索,不能替代 TCP 端口、HTTP 路径、会话授权和消息送达检查;本章不进行任何真实探测。
Go 的 net 包有 Dial、Listen 等建立网络连接或监听的入口,也提供 JoinHostPort 避免 IPv6 地址与端口拼接歧义。它们是 04.03 以后编写教学小模型时的标准库起点;现在先弄清调用前需要哪些参数、调用失败属于哪个层次。实际网络连接还涉及超时、取消、关闭和重试,不能仅凭 Dial 返回 nil 错误就宣称 IM 消息已保存、投递或已读。
八、完整纸上路径与分层练习
以一个完全虚构的题设串起章节:客户端 A 为 u-a 查询 c-a 历史;服务名 chat.example.test 在纸上解析表中得到 192.0.2.10;本机路由表选择某条出口;目标端口为 TCP 8080;教学服务若收到了请求,才检查身份、会话和历史范围。u-b 是否在线与这次历史查询的 DNS/连接结果不是同一事实。
1 识别应用目标:查询 c-a,调用者 u-a
2 取服务名 chat.example.test(仅虚构题设)
3 按纸上 DNS 表得到文档 IP 192.0.2.10
4 本机按目的 IP 前缀选择出口与下一跳
5 尝试 TCP 192.0.2.10:8080
6 成功建立连接后才可发送应用请求
7 若收到 HTTP 响应,核对响应者、状态与资源
8 再判断会话授权、返回历史和后续业务含义变式 A:第 3 步没有地址,止于解析;变式 B:第 5 步被拒绝,不能说 404;变式 C:第 7 步是 404,要查响应者与请求路径;变式 D:第 7 步是 403,要查应用访问合同。每个变式写“已知事实、仍未知事实、下一项证据”,不要把纸上说明填成真实执行日志。
分层练习:先回答,再核对反馈
1. `u-b` 是 IP 地址吗?
不是。它是虚构 IM 用户 ID,地址属于网络层。
2. `c-a` 与端口 8080 各表示什么?
前者是应用会话身份,后者是传输协议下的服务入口编号。
3. `chat.example.test` 在本章能真实解析吗?
没有这样的声称。它是保留测试域名,解析表仅在虚构题设中成立。
4. IPv4 有多少位?
32 位,通常写成四段点分十进制。
5. IPv6 有多少位?
128 位,通常写成以冒号分隔的十六进制形式。
6. `/24` 表示有 24 台主机吗?
不是。它表示 IPv4 前 24 位为共同前缀,剩余位的可用性要另看配置。
7. `192.0.2.10` 与 `192.0.2.20` 在本题 `/24` 中匹配吗?
匹配,前 24 位相同;这不证明两者实际可互通。
8. `198.51.100.20` 命中 `192.0.2.0/24` 吗?
不命中;若纸上只有这项和默认 /0,它走默认项。
9. DNS 返回 IP 就自动完成路由了吗?
没有。本机仍须依据目的地址选择可用路由与下一跳。
10. 有默认路由就一定能连接到服务吗?
不能保证。下一跳、后续路径、端口和应用仍可能失败。
11. TCP 8080 与 UDP 8080 是完全同一个入口吗?
不是。传输协议不同,即使端口数字相同也属于不同协议空间。
12. 服务端只监听一个端口就只能接受一个客户端吗?
不能这样推断。一个监听端点可接入多个不同客户端连接。
13. IPv6 地址带端口为什么常写成 `[2001:db8::10]:8080`?
用方括号隔开 IPv6 自身的冒号与后面的端口分隔符。
14. 服务只监听 `127.0.0.1`,别的机器凭同端口一定能连吗?
不能。它是本机 loopback 入口,跨机器还需合适的监听与网络路径。
15. 监听 `0.0.0.0` 就必然暴露在公网吗?
不必然。它表示本机 IPv4 接口上的监听意图,外部可达还受路由与访问控制等影响。
16. 域名解析失败时已发生 HTTP 404 吗?
在本题这条路径上没有。尚未得到地址,无法向该目标建立后续连接并取得响应。
17. “连接被拒绝”唯一证明服务进程没启动吗?
不能。也可能是端口或中间策略等因素,需进一步核对。
18. 收到 HTTP 404 至少说明什么?
有某个 HTTP 响应者处理了请求;仍需确认是否为预期服务和正确资源。
19. HTTP 403 能直接归因于 Linux 文件权限吗?
不能。它是某个 HTTP 响应者的访问拒绝,需要查应用或代理合同。
20. HTTP 200 是否证明 `u-b` 已读 `m-a`?
不证明。历史查询响应与设备接收、用户已读是不同业务事件。
21. `net.Dial` 成功能证明消息已持久化吗?
不能。它只覆盖连接建立的接口结果,后续请求和存储另需证据。
22. 本章的文档 IP 与 `.test` 域名适合直接部署教学 IM 吗?
不适合。它们只供静态说明,不构成真实网络配置或可达性保证。
来源与下一步
- RFC 5737:IPv4 文档地址、RFC 3849:IPv6 文档前缀、RFC 2606:保留测试域名:本章所有网络标签的使用边界。
- RFC 1034:域名概念、Linux
socket(7):名称与 socket 的职责。 - Go
net包:Dial、Listen、JoinHostPort等后续网络编程入口。
下一章04.03 HTTP 与 WebSocket 入门才用请求、响应和升级握手把本章的“名字→地址→连接”接到应用协议。进入前应能把 DNS 失败、连接拒绝、连接超时与 HTTP 404 写在四个不同阶段,并说明每项观察尚不能证明哪项 IM 业务状态。