type: note
title: Linux:起服务、停服务、改端口重启
date: 2026-11-04
description: 用普通用户起一个 Python HTTP 服务、日志落盘、后台运行;用 ps 找 PID、kill 停干净、ss 确认端口消失;换 8080 端口重启并验证。含分层定位的旧知识回收
tags: Linux, 进程, 服务, 试点
Linux:起服务、停服务、改端口重启
> 📌 GitHub:https://github.com/AR-firefly
笔记区
核心观点
**1. 起服务就是三件事**
一条命令要同时做到三样,才叫「起了一个真服务」:
| 要什么 | 靠什么 |
| ---------------------- | --------------- |
| 在后台跑,不占着终端 | 命令末尾加 `&` |
| 输出(含报错)落进文件 | `> 文件名 2>&1` |
| 在指定端口等人来连 | 命令里写端口号 |
`&` 是放到后台:敲完提示符立刻回来,程序继续跑。
`>` 是把正常输出写进文件,不显示在屏幕上。
`2>&1` 是把报错那股(`2`)并到正常输出那股(`&1`),两股合成一股一起进文件。
少了 `2>&1` 不是看不到报错,而是报错**只打在终端上、不进日志文件**------事后翻日志什么都看不到。
**2. 服务活着的硬判据:端口在 LISTEN**
`ss -lnt` 的输出里,`Local Address:Port` 那一列出现目标端口、`State` 是 `LISTEN`,才说明内核那边有人在等连接。
`0.0.0.0:8080` 表示绑在所有网卡上,本机用 `127.0.0.1:8080` 和 `172.17.158.107:8080` 都能连到。
**3. 停服务要认 PID,不能关终端**
-
关终端是对**这个终端里所有进程**下手,服务只是其中之一
-
用 `nohup` 起的服务,关终端反而不死,以为停了其实还在跑
-
认准 PID 再 `kill`,才是只打这一个
`kill` 之后终端会打印 `1+ Terminated ...`,但那只是作业结束的提示,**不能当停干净的证据**。要用 `ss -lnt` 或 `ps` 再确认一次。
**4. `ps` 不带参数只看两样少的东西**
| 命令 | 列哪些进程 | `CMD` 列显示什么 |
| -------- | ---------- | ---------------------------------------- |
| `ps` | 只当前终端 | 只有命令名 `python3` |
| `ps -e` | 所有进程 | 只有命令名 `python3` |
| `ps -f` | 只当前终端 | 完整命令行 `python3 -m http.server 8000` |
| `ps -ef` | 所有进程 | 完整命令行 |
所以拿 `ps | grep 'python3 -m http.server'` 什么都筛不到------不带 `-f` 时那列只有 `python3`,后面那串参数根本没显示。
`-e` = every(所有进程),`-f` = full(完整格式)。`-f` 补出来的列有:`UID`(属主)、`PPID`(父进程)、`C`(CPU 占比)、`STIME`(启动时间)。
**5. 日志一行怎么读**
`127.0.0.1 - - 04/Nov/2026 20:01:59 "HEAD / HTTP/1.1" 200 -`
读成一句话:**谁、什么时候、用什么方法要什么、结果怎样**。
| 片段 | 意思 |
| ------------------- | --------------------------------------------- |
| `127.0.0.1` | 谁来的 |
| `- -` | 两个占位(身份、用户名),HTTP 不带这两个信息 |
| `时间` | 什么时候 |
| `"HEAD / HTTP/1.1"` | 方法 + 路径 + 协议版本 |
| `200` | 结果,成功 |
| `-` | 回给对方的字节数,`HEAD` 不要正文所以是横杠 |
**6. 地址四段**
`http://127.0.0.1:8000/\` 拆成:协议 / 主机 / 端口 / 路径。
-
`127.0.0.1` 是本机回环,**只有本机能访问**
-
`172.17.158.107` 是网卡地址,**同一网络的其他机器能找到**
-
端口要写服务实际监听的那个,改 8080 地址就得跟着改
-
`80` 是 HTTP 默认端口,但 **1024 以下只有 root 能监听**,普通用户只能挑 1024 以上
**7. `http.server` 和 `curl` 是两头**
| 角色 | 谁 | 干什么 |
| ------ | ------------- | ------------------------------------ |
| 服务端 | `http.server` | 开店:在端口上等连接,有人来了就回应 |
| 客户端 | `curl` | 顾客:主动上门敲门,看有没有人应 |
服务端不会自己敲自己的门,所以验证「店开没开」必须另起一个客户端。浏览器同样能当这个客户端。
关键方法/流程
**起服务**
| 步 | 命令 | 判据 |
| --- | ------------------------------------------------- | ----------------------------------- |
| 1 | `mkdir -p ~/lab/d1` | 目录存在(`-p` 让它已存在也不报错) |
| 2 | `cd ~/lab/d1` | `pwd` 显示 `/home/ar-26710/lab/d1` |
| 3 | `python3 -m http.server 8000 > server.log 2>&1 &` | 打印 `1 <PID>`,提示符立刻回来 |
| 4 | `curl -I http://127.0.0.1:8000/\` | 第一行 `HTTP/1.0 200 OK` |
| 5 | `cat server.log` | 有一行访问记录 |
**停服务**
| 步 | 命令 | 判据 |
| --- | ---------------------------- | ------------------------------------------------- |
| 1 | `ps -ef \| grep http.server` | 找到 `python3 -m http.server 8000` 那行,记下 PID |
| 2 | `kill <PID>` | 终端打印 `Terminated` |
| 3 | `ss -lnt` | 端口不在列表里 |
**改端口重启**
同一个流程,三处一起改:起服务命令里的端口、访问地址里的端口。日志文件名如果也换(`server.log` → `app.log`),重定向那里一并改。
实战记录
**记录 1:起服务**
```
1 1282
```
`1` 是作业号(Shell 编的),`1282` 是 PID(内核编的)。提示符立刻回来,说明 `&` 生效。
**记录 2:kill 之后**
```
1+ Terminated python3 -m http.server 8000 > server.log 2>&1
```
**记录 3:换成 8080 之后**
```
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.14.4
Content-type: text/html; charset=utf-8
Content-Length: 340
```
`ss -lnt` 的最后一行:`LISTEN 0 5 0.0.0.0:8080 0.0.0.0:*`
**记录 4:`app.log` 里的访问记录**
```
127.0.0.1 - - 04/Nov/2026 20:01:59 "HEAD / HTTP/1.1" 200 -
```
服务起不来的三类原因(2026-11-05 补)
**判据总表**
| 类型 | 报错首词 | 进程状态 | 日志文件 | 第一步查 | 修 |
| ---------- | ------------------------ | ------------------- | ---------------------- | ------------------ | --------------- |
| 路径不存在 | `bash:` | 立刻 `Exit 1` | 没建出来 | 报错点名的那个路径 | `mkdir -p` |
| 没写权限 | `bash:` | 立刻 `Exit 1` | 没建出来 | 属主 + 权限位 | `chmod u+w` |
| 端口被占 | `Traceback` / `OSError:` | 跑了一段才 `Exit 1` | 建出来了,报错写在里面 | 谁占着端口 | `kill` 或换端口 |
**怎么分类:看报错首词**
-
`bash:` 开头 = **shell** 报的 = 命令没跑(卡在重定向那一步)
-
`Traceback` / `OSError:` 开头 = **程序自己**报的 = 跑起来了才撞墙
**第二个判据:`N PID` 后面跟什么**
起服务时 `&` 会先分配 PID,所以 `N 数字` 一定会打印。区别在下一行:
-
紧跟 `N+ Exit 1` = 进程已经退出
-
没有 `Exit` = 还活着
**1. 路径不存在**
-
命令:`python3 -m http.server 8000 > logs/app.log 2>&1 &`
-
现象:`bash: logs/app.log: No such file or directory` + `2+ Exit 1`
-
机制:shell 先打开 `>` 后面那个文件,打不开就不执行后面的命令
-
修:`mkdir -p logs`
**2. 没写权限**
-
现象:`bash: logs_ro/app.log: Permission denied`
-
权限 10 位 = `d` + 三组 `rwx`(属主 / 同组 / 其他人)
-
`dr-xr-xr-x` = 目录,属主 `r-x`(**没有 w**),同组 `r-x`,其他人 `r-x`
-
**目录的 `w` 管「能不能在里面新建、删除、改名文件」**;属主没有 `w`,自己照样写不进去
-
修:`chmod u+w 目录`(`u` 属主、`+` 加、`w` 写)
**3. 端口被占**
-
现象:`Traceback ... OSError: Errno 98 Address already in use`
-
程序跑起来了,走到 bind(绑端口)那一步才失败
-
查占用者:`ss -lntp | grep :端口`,输出 `users:(("python3",pid=NNN,fd=3))`
-
认人:`ps -p NNN -o pid,cmd`
-
修:`kill NNN`,或者换端口
-
`Errno 98` 是系统给「地址被占」编的号
**Traceback 怎么读**
-
`Traceback (most recent call last)` = 回溯,越往下越接近真凶
-
中间一行行 `File "...", line N, in 函数名` = 调用链
-
**最后一行 = 真正的原因**
**`2>&1` 在这类故障里的后果**
报错被送进日志文件,**屏幕上什么都看不到**,只有一个 `N PID`。看着像成功,其实已经死了。`cat 日志文件` 才看得到。
线索区(学完后合上材料,自问自答)
**Q: 起服务那条命令里,`&` 和 `2>&1` 各干什么?少了会怎样?**
A: `&` 放后台,少了要一直占着终端;`2>&1` 把报错并进正常输出那股,少了报错只打在终端上、不进日志文件。
**Q: 怎么判断一个服务真的停了?**
A: `ss -lnt` 里端口不在列表里。`kill` 后终端打印的 `Terminated` 不算证据。
**Q: 为什么 `ps | grep 'python3 -m http.server'` 什么都筛不到?**
A: 不带 `-f` 时 `CMD` 列只写命令名 `python3`,后面的参数不显示。
**Q: `ps -e` 和 `ps -f` 分别补什么?**
A: `-e` 补范围(所有进程,不只当前终端);`-f` 补格式(完整命令行 + `UID` / `PPID` / `C` / `STIME`)。
**Q: 日志一行 `127.0.0.1 - - 时间 "HEAD / HTTP/1.1" 200 -` 怎么读?**
A: 谁来的 / 两个占位 / 时间 / 方法+路径+协议 / 状态码 200 / 回包字节数(HEAD 无正文所以是横杠)。
**Q: `http://127.0.0.1:8000/\` 四段各是什么?为什么不用 80?**
A: 协议 / 主机 / 端口 / 路径。`127.0.0.1` 是本机回环,只有本机能访问。80 是默认端口但 1024 以下要 root。
**Q: `curl` 和 `http.server` 各是什么角色?**
A: `curl` 是客户端(去敲门),`http.server` 是服务端(在端口上等着)。服务端不会自己敲自己的门。
**Q: 为什么停服务要用 PID 而不是关终端?**
A: 关终端会杀掉这个终端里所有进程,而且 `nohup` 起的服务关终端不死,以为停了其实还在跑。
**Q: 起服务后终端只回了 `2 4256`,没报错,怎么判断它死没死?**
A: 看下一行有没有 `2+ Exit 1`。有 = 已经退出;没有 = 还活着。再配合 `ss -lnt` 看端口在不在。
**Q: `bash: xxx: No such file or directory` 和 `bash: xxx: Permission denied` 怎么分?**
A: 都是 shell 报的、命令都没跑。一个说路径不存在,一个说路径在但没权限。分别查路径、查属主和权限位。
**Q: 什么情况下报错会变成 `Traceback`?**
A: 程序真的跑起来了,运行中撞墙。比如端口被占,走到 bind 那一步才失败。
**Q: 端口被占,怎么找到占用者?**
A: `ss -lntp | grep :端口` 看 pid,`ps -p PID -o pid,cmd` 认人,再决定 kill 还是换端口。
总结(50字以内,用自己的话概括今天学到了什么)
起服务三样:后台跑、日志落文件、端口在听;停要认 PID,停完看 LISTEN;改端口地址跟着改。
复习卡片
| 概念 | 必学/了解 | 一句话 | 场景 |
| ------------------------ | --------- | ------------------------------------------------------- | ------------------ |
| `&` | 必学 | 命令末尾加 `&`,程序放后台,提示符立刻回来 | 起服务不占终端 |
| `>` | 必学 | 正常输出写进文件,不显示在屏幕上 | 日志落盘 |
| `2>&1` | 必学 | 报错那股并到正常输出那股,一起进文件 | 报错也要留在日志里 |
| `ps -ef` | 必学 | `-e` 所有进程、`-f` 完整命令行(含参数) | 找进程号 |
| `kill` | 必学 | 给指定 PID 发信号,默认终止 | 停服务 |
| `ss -lnt` | 必学 | 列出所有在监听的 TCP 端口,`LISTEN` 才算活着 | 判断服务在不在跑 |
| `curl -I` | 必学 | 发 HEAD 请求,只要响应头 | 验证服务回不回话 |
| `nohup` | 了解 | 挂断/关终端时不杀它;`man 1 nohup` | 长期跑的服务 |
| `pgrep` | 了解 | 按名字找进程,比 `ps \| grep` 少一条管道;`man 1 pkill` | 快速找 PID |
| `ss -lntp` | 了解 | 加 `-p` 显示进程名,要 `sudo`;`man 8 ss` | 看端口被谁占 |
| `Exit 1` | 必学 | 进程退出时留的状态码,0 正常、非 0 出错 | 判断进程死没死 |
| `Permission denied` | 必学 | 路径在,但当前身份没权限 | 日志写不进去 |
| `Address already in use` | 必学 | 字面:地址已被占用;常跟 `Errno 98` | 端口被占 |
| `Errno 98` | 必学 | `Err` 错误 + `no` 编号;98 专门绑「地址被占」 | 端口被占 |
| `chmod u+w` | 必学 | 改模式:`u` 属主、`+` 加、`w` 写 | 补目录写权限 |
| `Traceback` | 必学 | Python 报错的开头,越往下越接近真凶 | 分清「程序撞墙」 |
流程附加段
旧知识回收
| 概念 | 一句话 | 出处 |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------- |
| 四层各管什么 | 链路(这一小段路)/ 网络(IP 找路)/ 传输(敲门、送全)/ 应用(门开了说什么)。一开始把「连不上」答成应用层 | 复习第 1 问 |
| 分层的好处 | 不是「某层出错不影响别的」(底层断上面全废),是「换掉一层技术不用重写别的层」 | 复习第 2 问 |
| MAC 与 IP | 网卡自己的 MAC 全程不变;每一跳换的是**帧头里写的下一个接手人**。IP 是收件地址,一路不变 | 复习第 3 问 |
| `addr` vs `link` | `addr` 看地址(IP / IPv6),`link` 看网卡本身(状态、MAC、标志位)。`link` 里没有任何地址 | 复习第 4 问 |
| `ip route get` 的 `via` | **有 `via` = 交给下一跳中转 = 不同网段;没有 `via` = 直达 = 同网段** | 11-05 复习 |
| 两个地址判同段 | 必须带掩码。同一对地址,`/20` 下可能同段,`/24` 下可能就不同段 | 11-05 复习 |
| shell 与 `python3` | shell 是终端里读命令的那一层;`python3 -c "..."` 是让 shell 启动 python3 程序去跑代码。`-c` 是 python3 自己的选项 | 11-05 追问 |
今日产出验收
| 产出条 | 证据 | 结果 |
| ------------------------------ | ----------------------------------------------------- | ---- |
| 一个跑在 8080 的服务 | `ss -lnt` 最后一行 `0.0.0.0:8080`、`curl -I` 拿到 200 | 过 |
| 日志落在 `~/lab/d1/app.log` | `cat app.log` 有一行 `HEAD / HTTP/1.1" 200` | 过 |
| 说清停、起、换端口各用哪条命令 | 复盘三问答出 | 过 |
| 说清凭什么判断停干净了 | 「`ss -lnt` 里端口不在列表里」 | 过 |
| 分清三类起不来(11-05) | 报错首词 `bash:` vs `Traceback`;`Exit 1` 判据 | 过 |
| 独立排查一次端口被占(11-05) | 自己拼出 `grep 8000` / `kill` / 起服务 / `curl`,200 | 过 |