介绍
社区下载台提供 North Pier 实地笔记和花园志愿者简报。关闭下载台前,一位志愿者希望让已经接受的下载完成。第一个实现却会立即关闭连接。你将先获取一份完整、有用的文档,再准确观察立即停止会中断什么。
你需要了解 Go 函数、处理器和错误值,以及前两个项目介绍的 goroutine/channel 职责,或具备同等经验。本单元会介绍进程身份和 SIGTERM。两个具名终端是同一台机器上的不同会话。准备好的观察工具只记录本课程自行构建的服务器和 curl 子进程;你不必学习其原生跟踪格式。预计约 45 分钟,包括阅读和普通错误处理;这是作者估计。各单元独立初始化。
下载一份完整文档
本步骤中,你将获取一份完整、有用的文档,并核对其实际字节。
从 Downloads 开始。两个终端入口都只进入已有工作区;打开标签页不会重建场景。如果遇到普通的目录错误,以下可见命令可返回正确位置:
cd /home/labex/project/download-desk
阅读两份原始文本文件。它们包含不同的实用资料,并非同一个样本的两个名字。cat 显示文件内容,不修改文件。
cat documents/north-pier.txt documents/garden-route.txt
整个单元中,保持这些原件和所有准备文件不变。你可以构建 desk、启动具名的观察尝试,以及创建下载。本单元不修改 Go 源码。后续各单元都会提供独立的新副本。
切换到 Server。Go 可执行程序已放在其绝对路径。build 编译这个包;. 表示当前包,-o desk 指定构建后可执行文件的名称。使用构建出的二进制程序能明确进程身份,避免向 go run 包装进程发信号的混淆。
cd /home/labex/project/download-desk
/usr/local/go/bin/go build -o desk .
启动一次具名尝试。提供的观察器启动你的二进制程序,记录其真实进程、HTTP 请求、信号和原生退出状态;它并不实现优雅关闭。first 是尝试名称。观察器拒绝已有名称,以免静默覆盖先前的证据。
python3 desk.py serve first
等待 Ready. Use Downloads for client requests.。此终端会一直被占用,直到原进程退出。它打印的 PID 属于构建出的 Go 子进程,而非观察器。让 Server 保持运行,切换到 Downloads。
准备好的下载客户端执行真实 curl,记录其原生进程结果并保存实际输出。四个参数依次选择尝试、新输出标签、准备好的文档,以及每 32 字节的毫秒延迟。延迟 0 是普通的快速样例。标签 normal 对应 downloads/normal.txt。
python3 desk.py download first normal north-pier.txt 0
预期看到 Original curl native exit: 0。零表示传输完成,但不能单独证明内容正确。cmp 逐字节比较实际文件,相等时不输出任何内容。也请阅读保存下来的实用文档:
cmp documents/north-pier.txt downloads/normal.txt
cat downloads/normal.txt
如果客户端报告连接被拒绝,返回 Server 阅读已有输出。不要在同一端口反复启动另一个进程。如果 Go 报告构建错误,先纠正目录或对照准备文件,再重新构建。新 shell 不会继承另一个 shell 的变量,但这两个会话共享文件和已观察的尝试。
在已接受的下载期间停止原服务器进程
本步骤中,你将中断一次真正已被接受的传输,并区分客户端失败与服务器退出。
从 Downloads 开始,此时 Server 仍在运行 first。进程 ID(PID)标识当前运行的进程,但进程退出后,操作系统可能重用这个号码。观察器还会核对可执行文件路径、当前用户 ID,以及 /proc 中的 Linux 启动时钟计数,以区分原进程。只向本课程自行构建的进程发信号。不要使用 pkill、不要以观察器为目标,也不要修改平台进程或 shell 配置。
SIGTERM 是请求进程终止的普通信号。kill -TERM PID 将该请求发送给一个精确的 PID。它本身不会等待下载,也不能证明进程已经结束。准备好的 Go 程序收到此信号后,会立即调用 Close,然后从 main 返回。这是你将观察的行为,不是网络故障。
启动慢速传输前,先读完本步骤剩余部分,包括预期失败和恢复方法。 然后按顺序执行操作块;不要在这个有限时长的请求运行期间停下来学习下一个概念。对于这份文档,窗口约为半分钟,并非无限等待。
在后台启动一次有限时长的慢速下载。& 让此 shell 在客户端运行时仍可接受下一条命令;$! 是最后一个后台作业的进程 ID,赋值会保存这个观察器作业,以便稍后用 wait 读取其原生结果。公开的 300ms 延迟发生在每两次 32 字节写入之间,为阅读和切换标签页留出时间;这是受控的训练传输,不是性能测量。
python3 desk.py download first interrupted north-pier.txt 300 & download_job=$!
停止任何进程前,请观察器读取已经记录的原生请求。此命令不会发送替代请求或信号。它必须报告原服务器已经接受这个真实客户端,并且两者身份仍然存在。默认 curl 可能缓冲小文件的写入,因此输出文件暂时为空并不表示请求从未开始。
python3 desk.py accepted first interrupted
现在获取并检查原进程身份。$(...) 将此命令打印的 PID 存入 shell 变量;后面的带引号的 "$server_pid" 将它作为一个参数传入。辅助工具会拒绝过期的 PID/启动时间/可执行文件/UID 组合。
server_pid=$(python3 desk.py pid first)
python3 desk.py identity first
只有观察到已接受请求后,才发送精确信号:
kill -TERM "$server_pid"
读取原客户端结果。wait 等待这个 shell 的后台作业。下一条命令预期返回 18,并伴随 curl 关于缺失字节的消息。这是对失败传输的一次完整观察,不应使用成功标记掩盖这个命令的失败。
wait "$download_job"
echo $? 立即显示上一条命令的原生状态,预期为 18。之后成功执行的 cat 会替换该 shell 状态,因此请立即读取:
echo $?
cat downloads/interrupted.txt
与原件比较:
cmp documents/north-pier.txt downloads/interrupted.txt
本次比较预期返回 1,并报告部分文件提前结束。收到的文本以真实 North Pier 内容开头,但并不完整。因此,文件名匹配或文件非空,都不足以证明获得了一份完整可用的下载。切换到 Server,读取 Original server native exit: 0。正常退出的服务器仍可能中断其客户端。
返回 Downloads,保留两份结果。课程检查只读取已有观察记录和实际文件;它不会替你停止 现场进程,也不会补做缺失的中断过程。
如果等待太久,慢速传输在发信号前已经完成,就不要将它称为中断。读取其原生 0 结果,比较完整字节并保留文件。如果 first 仍在运行,用新标签(例如 interrupted2)启动同样的慢速命令,保存新的后台作业,并在发信号前对同一个标签执行 accepted。如果原服务器已经退出,切换到 Server,显式启动一个新尝试,例如 retry1,同时保留旧尝试;随后在 download、accepted、pid 和 identity 命令中使用这个尝试名称和新的输出标签。检查接受这些新名称。重复真实观察,不要复制部分文件。已完成或未知的传输,都不意味着可以再次向被重用的 PID 发信号。
下面是在同一个仍运行的 first 尝试中完整重试的步骤。仅在旧客户端真正完成后使用;保留 downloads/interrupted.txt。开始前读完以下所有操作块。 新标签会产生独立输出:
python3 desk.py download first interrupted2 north-pier.txt 300 & download_job=$!
python3 desk.py accepted first interrupted2
server_pid=$(python3 desk.py pid first)
python3 desk.py identity first
kill -TERM "$server_pid"
接下来的 wait 仍预期返回 18;请立即读取,然后比较新的实际部分文件(比较预期返回 1):
wait "$download_job"
echo $?
cmp documents/north-pier.txt downloads/interrupted2.txt
如果 first 已经退出,改在 Server 启动一个不同的尝试:
python3 desk.py serve retry1
收到就绪消息后,在 Downloads 使用以下完整序列,采用第三个新输出标签:
python3 desk.py download retry1 interrupted3 north-pier.txt 300 & download_job=$!
python3 desk.py accepted retry1 interrupted3
server_pid=$(python3 desk.py pid retry1)
python3 desk.py identity retry1
kill -TERM "$server_pid"
wait "$download_job"
echo $?
wait 应返回 18。保留实际输出,并验证它不完整(比较预期返回 1):
cmp documents/north-pier.txt downloads/interrupted3.txt
结束时保留已停止的原下载台和结果。正常下载的文件已经完整,仍可阅读;检查前不要留下替代监听器继续运行。下一个独立单元将介绍如何保全活动传输。
总结
你观察了一次真实的完整下载,然后将传输中断与对原服务器的精确停止联系起来。连接被拒绝、传输只收到一部分,以及进程正常退出,分别描述不同的事实。



