发布并使用照片亭服务

LinuxBeginner
立即练习

介绍

在 Maple Yard,访客希望取得少量照片预览或照片亭的完整相册。照片服务器已经正常运行,但访客不应需要一张印着 IP 地址和端口的纸条。你将发布两个具名服务,从客户端发现它们,并保存对应的图片集合,同时不影响咨询台。

你应能识别 IPv4 地址、主机名、端口、路径和终端所属角色,并且曾按照完整命令进行 HTTP 下载。建议先完成上一门活动网络项目。不需要 DNS 管理、XML 或编程经验。预计 60 分钟包含阅读和普通错误处理;这是作者估计,并非初学者实测时间。

Publisher、Client 和 New Client 是同一预备 LAN 上的隔离 Linux 网络节点,共享一个内核。Photo Shelf 用于预览已下载文件。本实验教授本地链路上的 mDNS 和 DNS-SD,不涉及公网 DNS、跨路由器发现、自动授权,也不保证与所有实体设备或浏览器兼容。示例图片是原创合成插画卡片,并非真实参与者的照片。

发现一个正常工作的服务

在这一步中,你将在发布任何新服务之前,先使用正常工作的咨询台。从 Client 开始。其终端起始目录为 /home/labex/project/photo-network/client;这个目录和 shell 与其他 Tab 保持独立。pwd 显示当前目录:

pwd

多播 DNS(mDNS)让相邻设备在同一本地链路上交换名称信息。这里的数据包使用 IPv4 多播地址 224.0.0.251 和 UDP 端口 5353。.local 后缀属于这种本地发现机制;不要把它加入平台的 hosts 文件,也不要将它当作公网 DNS 区域。

基于 DNS 的服务发现(DNS-SD)描述具名的服务实例。服务类型表示客户端要寻找什么:_http._tcp 表示通过 TCP 使用 HTTP。实例名称,例如 Information Desk,标识一项提供的服务。目标主机名标识提供服务的节点。端口选择正在监听的应用,path 元数据选择其中的资源。找到名称只是使用服务的开始。

avahi-browse 请求原生 Avahi 守护进程发现服务。-r 将每个实例解析成连接信息,-t 在浏览完成后退出,-p 输出以分号分隔的字段,-k 保留原始服务类型名称,而不是便于阅读的翻译名称:

avahi-browse -rtpk _http._tcp

预期会看到以 = 开头、包含以下字段的已解析记录:

=;eth0;IPv4;Information\032Desk;_http._tcp;local;desk.local;10.93.0.10;8080;"path=/welcome/index.json"

Avahi 还可能为新发现的实例输出 + 记录。在可解析输出中,\032 表示空格。依次读取已解析记录中的实例、类型、域、目标主机名、地址、端口,以及 TXT 元数据。输出顺序和转义方式可能有所变化。原生守护进程通过这条 LAN 接收记录;这里没有预先准备的发现列表。

使用提供的 photo-get 客户端,按实例名称保存集合。引号让含空格的名称成为一个参数。第二个参数是此终端工作区中的输出文件夹:

photo-get "Information Desk" desk

photo-get 会再次进行真实的 Avahi 浏览,解析这个准确实例,打印连接端点,取得它广播的 JSON 索引和其中列出的每张 PNG,解码全部图片,然后保存收到的字节。它不会从站点计划中查找 IP、端口或路径。索引列出图片文件名;这是这些服务采用的应用约定,而非通用 DNS-SD 格式。预期看到 Saved 1 real images,集合保存在 desk 文件夹中。

切换到 Photo Shelf,选择 Client,重新加载已保存文件。你应看到 Welcome to Maple Yard 卡片。预览器只读取这个客户端工作区保存的文件;它不会请求服务器或补充缺失图片。Download image 链接返回同一个已保存文件。

Photo Shelf 中已保存的咨询台卡片

Client 选项标明当前工作区。这张咨询台卡片是你添加照片亭时需要保留的正常参考。

如果浏览结果为空,先检查服务类型的准确拼写以及当前是否在 Client,然后重新浏览。Daemon not running 表示发现客户端无法连接其已准备的守护进程,与空结果不同。如果 photo-get 无法解析名称,请将拼写和引号与已解析记录对照。连接被拒绝表示已找到地址,但该端口没有接受连接的程序。HTTP 404 表示已到达服务器,但资源路径不存在。JSON 或图片解码错误表示返回内容不合适。不要通过 hosts 条目或手动复制图片来替代这些问题的解决。

根据完整模板发布照片亭

在这一步中,你将广播已有的预览服务器。切换到 Publisher。其终端起始目录为 /home/labex/project/photo-network/services。cat 显示文本文件,../ 表示父目录:

cat ../stations.tsv

这份业务计划描述已准备好的真实监听服务。Photo Booth Preview 位于 publisher.local,使用端口 8081,资源为 /preview/index.json。完整相册是另一个监听服务和资源。咨询台位于另一个节点,必须保持不变。

读取尚未完成的预览定义:

cat preview.service

这里的 .service 文件使用 XML:开始标签和结束标签包围各个值。service-group 包含显示用的 name;其中的 service 提供 type、port 和 txt-record。发布定义不会创建 Web 服务器、图片集合或访问权限。这些应用已经在运行。

下面的 here-document 将写入这个完整的小文件。> 会替换文件原有内容。带引号的 'XML' 使正文保持字面值;结束标记 XML 必须单独位于一行的开头。复制整个代码块:

cat > preview.service <<'XML'
<?xml version="1.0" standalone="no"?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name>Photo Booth Preview</name>
  <service>
    <type>_http._tcp</type>
    <port>8081</port>
    <txt-record>path=/preview/index.json</txt-record>
  </service>
</service-group>
XML

读取已保存的定义:

cat preview.service

课程提供的 photo-load 命令会先解析两个可编辑 XML 文件,再只请求 Publisher 的 Avahi 守护进程重新加载。它不会重启咨询台或业务服务器:

photo-load

预期看到 Reload requested for the photo publisher。等待几秒,让名称探测和注册完成。解析成功只能确认 XML 结构,不能证明广播的端口或路径正确。如果缺少结束标签,photo-load 会报告文件名和解析错误,不发送重新加载请求。读取文件,恢复上面完整的代码块,再运行 photo-load。无需重置环境。

切换到 Client,再次浏览:

avahi-browse -rtpk _http._tcp

找到 Photo Booth Preview,以及它的 publisher.local 目标、端口 8081 和 /preview/index.json。保存并解码真实集合:

photo-get "Photo Booth Preview" preview

预期得到一张预览图片。在 Photo Shelf 选择 Client,重新加载,查看预览卡片与已有的咨询台卡片。服务即使出现在列表中,若不能取得正确图片,工作仍未完成。

区分两个服务

在这一步中,你将在同一节点发布完整相册,并区分两个实例。切换到 Publisher。两者都使用 _http._tcp 和 publisher.local,但相册使用端口 8082 及 /album/index.json。它包含三张图片,与只有一张图的预览不同。

使用已经学过的 here-document 语法,写入独立的定义:

cat > album.service <<'XML'
<?xml version="1.0" standalone="no"?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name>Photo Booth Full Album</name>
  <service>
    <type>_http._tcp</type>
    <port>8082</port>
    <txt-record>path=/album/index.json</txt-record>
  </service>
</service-group>
XML
photo-load

切换到 Client。浏览并分别读取每条已解析记录:

avahi-browse -rtpk _http._tcp

两个实例名称应当不同。相同的主机名并不表示相同的端口或资源。将相册下载到自己的文件夹中,同时保留预览:

photo-get "Photo Booth Full Album" album

预期看到三张 PNG 已解码,以及 Saved 3 real images。在 Photo Shelf 选择 Client 并重新加载。相册和预览应分别显示各自保存的文件。

现在练习识别错误资源,不编辑或删除已有的正确集合。下面故意使用一个不存在的实例名称,应在任何下载发生前失败:

photo-get "Photo Booth Missing" missing

预期看到 Download stopped: Expected one resolved instance,并以非零状态退出。这是故意安排的失败。再次使用实际解析出的相册名称来恢复:

photo-get "Photo Booth Full Album" album

如果你广播了错误的端口或路径,请将该实例的解析记录与 stations.tsv 对照。只在 Publisher 修正相应的 .service 文件,使用所示完整代码块,运行 photo-load,然后回到 Client 重新浏览并下载。错误的监听端口可能拒绝连接;错误路径可能产生 HTTP 404;能够到达但内容不同的集合可能成功解码,却仍是错误的业务结果。检查集合标题和文件名,而不只看退出状态是否为零。

Avahi 会广播更新和撤销信息。更新传播期间,客户端可能短暂保留旧记录。加载后等待几秒并重新浏览,不要继续使用复制下来的旧端点。下一步将从独立的客户端守护进程和工作区进行检查。

从另一个客户端使用结果

在这一步中,你将使用另一个网络身份和独立的 Avahi 守护进程。切换到 New Client。其起始目录为 /home/labex/project/photo-network/new-client;默认不会共享第一个客户端的 shell 变量或已保存集合。打开 Tab 不会重置发布端或创建广播。

从这个客户端浏览,不要复制第一个客户端的记录:

avahi-browse -rtpk _http._tcp

读取三个已解析实例的完整对应关系。预览和完整相册的目标相同,但端口和路径不同。咨询台有自己的目标。从此客户端下载全部三个集合:

photo-get "Photo Booth Preview" preview
photo-get "Photo Booth Full Album" album
photo-get "Information Desk" desk

预期得到一张预览图、三张相册图和一张咨询台卡片。每次调用都会再次解析具名实例,并打印实际使用的端点。这些命令不会配置静态 IP 发现。

切换到 Photo Shelf,选择 New Client 并重新加载。检查每张图片和集合标题。在一张已保存图片卡片上选择 Download image;下载的图片应与显示的已保存卡片一致。预览器不会静默复制第一个客户端的作品,也不会补齐缺失文件。在 Client 和 New Client 之间切换,查看各自独立的集合。

独立客户端保存了全部三个集合

找到 New Client 选项、三张相册卡片、咨询台卡片和独立的预览卡片。每个 Download image 链接都对应一个真实保存的文件。

如果缺少某个集合,请返回 New Client,先检查当前广播,再重复该集合的下载。如果已保存的 PNG 缺失或不可读,预览器会报告,而不会替换它。先修正发布信息或连接,再次运行 photo-get 取得完整原始集合。只有完整索引和全部图片都已获取并解码,下载才算成功。

你已经把服务发布与实际使用连接起来:三个可区分的实例、正确的当前端点、两个客户端上的真实文件,以及仍然可用的咨询台。发现机制提供连接信息,不提供身份认证,也不保证发现的服务值得信任。

总结

你浏览了原生 mDNS/DNS-SD 记录,区分了实例名称和主机名,并通过独立端口和路径元数据发布两个 HTTP 服务。你使用每次真实发现结果下载可解码的图片,在独立客户端重复流程,并保留了咨询台。发现记录和成功连接是两种不同证据;正确保存的内容才使结果完整。