你真的会用lsof吗?一个被低估的神器级指令(对比netstat & ss)

引言:从一个经典问题开始

在Linux系统管理和应用排错的日常工作中,我们几乎每天都会遇到一个经典问题:"哪个进程占用了我的8080端口?"

对于这个问题,许多经验丰富的技术员会下意识地敲出 netstat -tulnp | grep 8080 。这个命令组合确实有效,它像一位老朋友一样,陪伴我们走过了许多个排错的夜晚。然而,随着Linux内核的发展和工具链的演进,这位"老朋友"不仅显得有些过时(netstat在许多现代发行版中已被标记为弃用),而且在解决问题的哲学和效率上,也面临着更强大对手的挑战。

这个更强大的对手,就是我们今天的主角------lsof

lsof,全称"List Open Files"(列出打开的文件),是一个在功能上远超其名的"神器"。很多技术员可能只在需要查找端口占用时偶尔使用它,甚至完全忽略了它的存在,仅仅满足于netstat提供的功能。这是一种巨大的资源浪费。lsof的强大之处在于,它完美诠释了Linux/Unix设计的核心哲学:"一切皆文件 (Everything is a file)" 。在Linux的世界里,无论是一个普通的文本文件、一个目录、一个硬件设备、一个网络套接字(socket),还是一个进程间通信的管道,都被抽象为文件。因此,一个能够"列出所有打开的文件"的工具,实际上就拥有了洞察整个系统内部运作的"上帝视角"。

准备好了吗?让我们一起揭开lsof的神秘面纱,探索这个被大多数人严重低估的命令行瑰宝。

第一章:lsof - 不仅仅是"列出打开的文件"

在深入探讨lsof的具体用法之前,我们必须先理解它的立身之本------它所依据的Linux核心设计哲学,以及它为我们呈现的信息究竟意味着什么。

1.1 核心哲学:Linux中"一切皆文件"的终极体现

正如引言所述,lsof的强大根植于"一切皆文件"的哲学 。这个概念意味着,内核将所有I/O资源都抽象成一个统一的接口------文件描述符(File Descriptor)。当你打开一个文件、监听一个端口、连接一个数据库,甚至加载一个动态链接库时,你的进程都会获得一个或多个文件描述符,作为与这些资源交互的句柄。

lsof命令的作用,就是遍历系统中所有活跃进程,并列出它们当前持有的每一个文件描述符,以及这个描述符所指向的底层实体(即"文件")的详细信息 。这使得lsof的能力范围异常宽广:

  • 普通文件与目录:一个进程正在读取配置文件,或写入日志文件。
  • 块设备与字符设备 :一个进程正在访问硬盘分区 (/dev/sda1) 或终端 (/dev/tty)。
  • 网络套接字 (Sockets):一个Web服务器正在监听80端口,或者一个客户端正在通过TCP连接访问远程服务。这正是我们解决端口占用问题的关键。
  • 动态链接库 (Shared Libraries) :一个正在运行的程序加载的.so文件。
  • 进程间通信 (IPC):如管道 (Pipes)、UNIX域套接字 (UNIX Domain Sockets)。
  • 内核数据结构:例如进程的工作目录 (cwd)、程序的执行文本 (txt)、内存映射文件 (mem) 等。

理解了这一点,你就会明白,lsof不仅仅是一个"网络工具"或"文件工具",它是一个全面的系统状态诊断工具

1.2 基础语法与输出解读:揭示信息的宝藏

在终端中直接执行lsof(通常需要sudo权限以获取所有进程信息 ,你会看到海量的信息滚屏而过。初看之下可能会让人望而生畏,但一旦你理解了其输出的结构,这片信息海洋就会变成一个蕴含答案的宝藏。

让我们执行一个简单的lsof命令,并截取其中几行来详细解读其输出列的含义:

复制代码
sudo lsof | head -n 5

示例输出:

复制代码
COMMAND     PID   TID TASKCMD              USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
systemd       1                            root  cwd       DIR              253,1      4096          2 /
systemd       1                            root  rtd       DIR              253,1      4096          2 /
systemd       1                            root  txt       REG              253,1   1700616   17569911 /usr/lib/systemd/systemd
systemd       1                            root  mem       REG              253,1   2133224   17180295 /usr/lib64/libm-2.28.so

下面是对每一列的详细解释:

  • COMMAND : 打开该文件的进程所执行的命令名称。通常是可执行文件的名字,如systemdsshdnginx
  • PID: 进程ID (Process ID)。这是系统中标示一个进程的唯一数字。
  • TID: 线程ID (Thread ID)。如果一个进程有多个线程,此列会显示线程ID。对于单线程进程,此列为空。
  • TASKCMD : 任务(线程)的命令名称。通常与COMMAND相同。
  • USER: 运行该进程的用户。
  • FD (File Descriptor) : 文件描述符。这是理解lsof输出的核心。它有多种形式:
    • 数字+字母 : 如3u4r。数字是内核分配给进程的文件描述符编号。字母表示其访问模式:r表示读 (read access),w表示写 (write access),u表示读写 (read and write access)。
    • cwd: Current Working Directory,表示进程当前的工作目录。
    • rtd: Root Directory,根目录。
    • txt: Program Text,表示程序的可执行文件本身。
    • mem: Memory-mapped file,内存映射文件,通常是加载的共享库。
    • mmap: Memory-mapped device。
    • pd: Parent directory。
    • ...等等。man lsof可以查看所有类型。
  • TYPE : 文件的类型。这是另一个关键列,它告诉我们正在处理的是什么类型的"文件":
    • REG: Regular file,普通文件。
    • DIR: Directory,目录。
    • CHR: Character special file,字符设备文件。
    • BLK: Block special file,块设备文件。
    • INET: Internet socket,网络套接字(IPv4/IPv6)。
    • UNIX: UNIX domain socket。
    • FIFO: Named pipe。
  • DEVICE: 设备的编号,格式为主设备号,次设备号。这对于磁盘文件很有用。
  • SIZE/OFF: 文件的大小(对于普通文件)或文件偏移量(对于网络连接,可能是TCP/UDP的内部状态信息)。单位是字节。
  • NODE: 文件的索引节点号 (inode number)。这是文件系统内部标识一个文件的唯一编号。
  • NAME: 文件的确切路径或网络连接的描述。这是我们最常关注的列。对于网络文件,它会显示源地址:源端口->目的地址:目的端口 (STATE)。

掌握了这些列的含义,你就拥有了解读lsof输出的"解码器"。现在,让我们进入实战,看看如何运用这个强大的工具解决实际问题。

1.3 安装与权限:准备工作

在绝大多数Linux发行版中,lsof都是预装的。如果你的系统碰巧没有,可以通过包管理器轻松安装:

  • Debian/Ubuntu : sudo apt-get update && sudo apt-get install lsof
  • CentOS/RHEL/Fedora : sudo yum install lsof or sudo dnf install lsof

关于权限lsof可以由任何用户执行,但非root用户只能看到自己启动的进程所打开的文件。为了获得完整的系统视图,特别是为了诊断系统服务(如Web服务器、数据库等)的问题,你必须使用root用户或sudo来执行lsof 。这是因为内核的安全机制限制了普通用户窥探其他用户进程内部信息的能力。在本文后续的所有示例中,我们都默认使用sudo lsof以确保获取最全面的信息。

第二章:lsof 实战场景深度探索

理论知识是基础,但真正的掌握来自于实践。本章将通过一系列精心设计的实战场景,一步步展示lsof在不同领域的强大应用。每个场景都将包含问题描述、命令执行、输出分析和原理解释。

2.1 网络连接诊断:端口占用与网络排错的瑞士军刀

这是lsof最广为人知的应用场景,但其能力远不止于此。

场景一:精准定位端口占用进程 (经典问题)
  • 问题: 我的应用程序启动失败,提示"Address already in use",我需要立刻找出是哪个进程占用了8080端口。

  • 命令 : sudo lsof -i :8080

    • -i: 这是lsof用于网络文件查询的核心选项。
    • :8080: 指定端口号。冒号是必需的。
  • 示例输出:

    复制代码
    COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    java    12345  myuser  42u  IPv6 123456      0t0  TCP *:8080 (LISTEN)
  • 输出分析:

    • COMMAND: java,说明是一个Java程序。
    • PID: 12345,这是罪魁祸首的进程ID。
    • USER: myuser,由myuser用户启动。
    • TYPE: IPv6,表示这是一个IPv6套接字(在现代内核中,IPv6套接字通常可以同时接受IPv4和IPv6的连接)。
    • NAME: *:8080 (LISTEN),这部分信息至关重要。*表示它正在监听所有网络接口(0.0.0.0)上的8080端口,状态是LISTEN(监听中)。
  • 解决方案 : 现在你有了PID 12345,可以轻松地处理它:

    • 调查 : ps -ef | grep 12345,查看这个Java进程的完整命令行,确认它是什么应用。

    • 终止 : 如果确认是无用进程,kill 12345kill -9 12345

  • 深度解析 : lsof -i选项非常灵活,它可以组合协议、IP地址和端口:

    • sudo lsof -i TCP: 列出所有TCP连接 。
    • sudo lsof -i UDP: 列出所有UDP连接。
    • sudo lsof -i @1.2.3.4: 列出所有与IP地址1.2.3.4相关的连接。
    • sudo lsof -i TCP:22: 列出所有TCP协议的22端口连接(即SSH连接)。
场景二:提升查询效率,避免不必要的等待
  • 问题 : 在一个繁忙的服务器上执行lsof -i时,我发现命令有时会卡住几秒钟甚至更久才返回结果。

  • 原因 : lsof默认会尝试将IP地址反向解析为主机名,并将端口号解析为服务名(例如,80解析为http)。这个过程依赖于DNS查询和/etc/services文件查找,当网络延迟或DNS服务器响应慢时,就会导致命令执行缓慢。

  • 命令 : sudo lsof -n -P -i :8080

    • -n (No hostname resolution): 禁止将网络地址转换为主机名 。
    • -P (No port name resolution): 禁止将端口号转换为服务名 。
  • 示例输出对比:

    • 不带 -n -P : nginx 5432 root 6u IPv4 65432 0t0 TCP myhost.example.com:http (LISTEN)
    • -n -P : nginx 5432 root 6u IPv4 65432 0t0 TCP *:80 (LISTEN)
  • 最佳实践 : 在几乎所有的网络排错场景中,我们都更关心原始的IP和端口号。因此,强烈建议始终将-n-P选项与-i一起使用,养成这个习惯将为你节省大量宝贵的排错时间。

2.2 进程与文件句柄分析:深入进程内部

lsof能够揭示一个进程与系统交互的所有秘密。

**场景三:查看特定进程打开了哪些"文件"**‍
  • 问题 : 我有一个Nginx worker进程(PID为6789),我想知道它当前正在处理哪些请求,访问了哪些日志文件,加载了哪些配置文件。

  • 命令 : sudo lsof -p 6789

    • -p: 指定进程ID。
  • 示例输出 (节选):

    复制代码
    COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
    nginx    6789 http  cwd    DIR              253,1     4096        2 /
    nginx    6789 http  rtd    DIR              253,1     4096        2 /
    nginx    6789 http  txt    REG              253,1  3500000 12345678 /usr/sbin/nginx
    nginx    6789 http  mem    REG              253,1   200000  9876543 /lib64/libpcre.so.1
    nginx    6789 http    1u   REG              253,1        0 23456789 /var/log/nginx/access.log
    nginx    6789 http    2u   REG              253,1        0 34567890 /var/log/nginx/error.log
    nginx    6789 http    6u  IPv4              65432      0t0      TCP *:80 (LISTEN)
    nginx    6789 http    7u  IPv4              65433      0t0      TCP 192.168.1.100:80->10.0.0.5:54321 (ESTABLISHED)
  • 输出分析: 这个输出就是一份Nginx worker进程的"活动报告":

    • FDcwd, rtd, txt, mem的行:显示了进程的工作目录、根目录、可执行文件本身以及加载的动态库。
    • FD1u2u的行:显示了它的标准输出和标准错误被重定向到了access.logerror.log
    • FD6u的行:显示它正在监听80端口。
    • FD7u的行:显示它正在处理一个来自10.0.0.5的已建立(ESTABLISHED)的连接。
  • 应用场景拓展:

    • 按命令名查询 : 如果你不知道PID,但知道命令名,可以使用-c选项,例如sudo lsof -c nginx ,它会列出所有名为nginx的进程打开的文件。
    • 按用户查询 : sudo lsof -u mysql,查看mysql用户启动的所有进程打开了哪些文件,这对于权限审计非常有用。

2.3 文件系统问题排查:运维的救星

这是lsof一个经常被忽略但极其强大的功能领域。

场景四:解决"Device or resource busy"卸载失败
  • 问题 : 我想通过umount /data命令卸载一个挂载点,但系统返回错误"umount: /data: target is busy."。某个进程仍然在使用这个挂载点下的文件,导致卸载失败。

  • 命令 : sudo lsof /data

    • 直接在lsof后跟上目录或文件名,它会找出所有打开了这个文件或这个目录下文件的进程。
  • 示例输出:

    复制代码
    COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
    bash    22334  myuser  cwd    DIR  253,3     4096 123456 /data/logs
    tail    22556  myuser    3r   REG  253,3 10240000 654321 /data/logs/app.log
  • 输出分析:

    • 第一行显示,myuser用户的一个bash进程(PID 22334)的当前工作目录(cwd)在/data/logs下。这是最常见的原因:有人在终端里cd到了这个挂载点下面
    • 第二行显示,同一个用户的tail进程(PID 22556)正在读取/data/logs/app.log文件。
  • 解决方案:

    1. 通知myuser用户,让他退出cd的那个目录(例如,cd ~)。
    2. kill 22556,终止那个tail进程。
    3. 再次尝试umount /data,此时应该就能成功了。
  • 深度拓展:

    • sudo lsof +D /data: 使用+D可以递归地列出目录下所有被打开的文件和子目录。这在处理复杂的嵌套目录时非常有用。
场景五:追查"幽灵"文件,释放被占用的磁盘空间
  • 问题 : 我删除了一个巨大的日志文件(rm large.log),但df -h显示磁盘空间并没有被释放。为什么?

  • 原因: 在Linux中,删除一个文件实际上是删除了指向其inode的目录条目。如果此时仍有进程持有这个文件的文件描述符,那么文件的inode和其占用的数据块就不会被释放,直到最后一个持有该文件描述符的进程关闭它。这个文件就成了一个"幽灵"文件:在文件系统中看不到它,但它依然占用着磁盘空间。

  • 命令 : sudo lsof | grep '(deleted)'

  • 示例输出:

    复制代码
    java      9876   tomcat    5w      REG              253,1  5368709120   12345678 /path/to/large.log (deleted)
  • 输出分析:

    • 这一行清晰地显示,java进程(PID 9876)仍然以写模式(5w)打开着一个已经被删除((deleted))的文件/path/to/large.log。文件大小为5GB (5368709120字节)。
  • 解决方案:

    • 最安全的方法是正常重启java应用 (PID 9876)。重启后,进程会释放所有旧的文件句柄,内核发现这个被删除文件的引用计数降为0,就会立即回收其占用的磁盘空间。
    • 高风险方法 (不推荐在生产环境使用):如果你能通过调试工具(如gdb)连接到该进程,并手动关闭那个文件描述符(FD为5),也能释放空间。但这非常复杂且危险。
  • 这个场景完美地体现了lsof的不可替代性。其他任何工具都很难如此直观地帮你定位到这类问题。

2.4 结合其他命令:构建强大的命令行管道

lsof-t选项(terse output)使其成为命令行管道中的完美组件。它只会输出PID,没有其他任何额外信息。

  • 场景: 快速杀死监听8080端口的所有进程。
  • 命令 : sudo kill -9 $(lsof -t -i :8080)
  • 分解 :
    1. lsof -t -i :8080: 这部分命令会执行查询,但只输出一个或多个PID,每个PID占一行。
    2. $(...): 这是一个命令替换,shell会先执行括号内的命令,然后将其标准输出结果作为参数插入到外部命令中。
    3. kill -9 ...: kill命令接收到来自lsof的PID列表,并强制终止它们。

这是一个极其高效和精确的操作,比先lsof看PID,再手动kill要快得多。

第三章:对比分析:lsof vs. netstat vs. ss

现在我们已经深入了解了lsof,是时候将它与我们熟悉的netstatss进行一场公正的对比了。我们将从功能、效率和使用哲学三个维度进行剖析。

3.1 netstat:昔日的王者

netstat是一个经典的、功能全面的网络信息显示工具 。它能显示路由表、网络接口信息、网络连接等等。我们最常用的组合是netstat -tulnp

  • -t: TCP
  • -u: UDP
  • -l: Listening sockets
  • -n: Numeric (don't resolve names)
  • -p: Show PID/Program name

查找端口占用 (8080) 的 netstat 方式:

复制代码
sudo netstat -tulnp | grep ":8080"

示例输出:

复制代码
tcp6       0      0 :::8080                 :::*                    LISTEN      12345/java

优点:

  • 家喻户晓: 几乎所有用过Linux的人都知道它,相关文档和教程铺天盖地。
  • 功能全面 : 除了查看连接,还能看路由表 (-r)、接口统计 (-i) 等。

缺点:

  • 已被弃用 (Deprecated) : 在许多现代Linux发行版(如RHEL 7+)中,net-tools包(包含netstat)已不再默认安装。官方推荐使用iproute2套件中的工具(如ss, ip addr)来替代 。
  • 效率较低 : netstat通过读取和解析/proc文件系统下的多个文件(如/proc/net/tcp)来收集信息。当系统连接数非常多时,这个过程会变得相对缓慢 。
  • 信息耦合 : 为了找到PID,你必须使用-p选项,并且输出结果是拼接在一起的,通常需要grep, awk等工具进行二次处理才能在脚本中使用。

3.2 ssnetstat的现代继任者

ss (socket statistics) 是iproute2工具包的一部分,被设计为netstat的直接替代品,特别是在套接字相关的查询上 。

查找端口占用 (8080) 的 ss 方式:

复制代码
sudo ss -ltnp | grep ":8080"
  • -l: Listening
  • -t: TCP
  • -n: Numeric
  • -p: Processes

示例输出:

复制代码
LISTEN    0      128          [::]:8080                 [::]:*     users:(("java",pid=12345,fd=42))

优点:

  • 性能卓越 : ss直接通过内核的netlink套接字接口获取信息。这是一种高效的内核-用户空间通信机制,比解析文本文件的netstat快得多,尤其是在高负载服务器上,性能优势非常明显 。
  • 信息更丰富 : ss可以显示比netstat更详细的TCP状态信息和内部计时器。
  • 现代标准 : 作为iproute2的一部分,它是现代Linux网络管理的标准工具。

缺点:

  • 领域专一 : ss是一个纯粹的网络工具 。它的设计目标就是高效地查询套接字信息。它无法回答"哪个进程占用了/data目录?"这类与文件系统相关的问题。

3.3 lsof:不同的维度,更广的视角

现在,让我们把lsof放回对比中。

查找端口占用 (8080) 的 lsof 方式:

复制代码
sudo lsof -nP -i :8080

示例输出:

复制代码
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
java    12345  myuser  42u  IPv6 123456      0t0  TCP *:8080 (LISTEN)
核心差异:哲学与范围

这是三者最本质的区别:

  • netstat/ss : 它们的视角是自底向上 的,从网络协议栈 出发。它们问内核:"嘿,告诉我所有关于TCP/UDP套接字的事情。" 进程信息 (-p) 只是附带关联上的。它们是专业的"网络审查员"。
  • lsof : 它的视角是自顶向下 的,从进程 出发。它问内核:"嘿,告诉我系统中所有进程都打开了哪些'文件'?" 而网络套接字恰好是"文件"的一种 。lsof是一个通用的"系统侦探"。

这个哲学的不同,导致了它们能力范围的巨大差异。

场景对比表格

为了更直观地展示,我们用一个表格来总结:

功能 / 场景 lsof netstat ss 备注
主要目的 列出进程打开的文件 显示网络状态信息 显示套接字统计信息 哲学的根本不同
范围 极广 (文件, 目录, 设备, 网络, IPC...) 较广 (网络连接, 路由, 接口) 专一 (仅网络套接字) lsof是通用工具
查找端口占用 非常擅长 (-i :port) 擅长 (-p + grep) 擅长 (-p + grep) lsof语法最直接
查询性能 中等 较慢 极快 ss在海量连接下优势明显
卸载文件系统排错 唯一选择 无法做到 无法做到 lsof /path是独门绝技
追查已删除文件 唯一选择 无法做到 无法做到 grep '(deleted)'是杀手锏
查看进程打开的所有资源 非常擅长 (-p PID) 无法做到 无法做到 提供进程的全景视图
脚本友好性 (-t选项) 低 (需awk/sed处理) 低 (需awk/sed处理) -t为自动化而生
系统预装情况 通常预装 逐渐被移除 现代标准 netstat是历史遗留

第四章:结论与最佳实践

经过前面的深度剖析和对比,我们可以得出以下结论,并形成一套清晰的最佳实践工作流。

我们不应该简单地问"哪个工具最好?",而应该问"在当前场景下,哪个工具最合适?"

  1. **lsof:首选的"问题定位器"**‍

    • 当你遇到一个未知 的问题,特别是那些"为什么...不行?"类型的问题时,lsof应该是你的第一选择。

    • ‍**"哪个进程占用了端口X?"** ‍ -> sudo lsof -nP -i :X。语法最直接,语义最清晰。

    • ‍**"为什么无法卸载/data目录?"** ‍ -> sudo lsof /data。这是它的专属领域。

    • ‍**"为什么删除大文件后空间没释放?"** ‍ -> sudo lsof | grep '(deleted)'。无可替代。

    • ‍**"我想全面了解进程Y在干什么?"** ‍ -> sudo lsof -p <PID_Y>。提供最全面的进程活动视图。

  2. **ss:高效的"网络状态监视器"**‍

    • 当你的目标是监控和统计网络状态 ,而不是定位某个具体问题时,ss是王者。
    • ‍**"我想快速列出所有监听中的TCP端口"** ‍ -> ss -ltn。速度远超netstatlsof
    • ‍**"我想查看所有到Web服务器的ESTABLISHED连接,并分析其状态"** ‍ -> ss -tan 'sport = :80'ss提供了强大的过滤功能和详细的TCP信息,适合做网络性能分析。
    • 脚本中需要批量获取网络连接信息进行分析 -> 使用ss,因为它性能最好,对系统负载最小。
  3. **netstat:值得尊敬的"退休老兵"**‍

    • 在一些非常古老的、没有ss的系统上,你仍然需要依赖netstat
    • 对于习惯了netstat命令和输出格式的老一辈系统管理员来说,它依然可用。
    • 但对于新人,没有理由再去优先学习netstat 。应该直接学习sslsof

我的推荐工作流

  1. 日常排错,优先lsof :遇到端口占用、文件句柄泄露、磁盘无法卸载等具体问题,第一时间想到lsof。它的通用性和深度能解决80%以上的问题。
  2. 网络监控,专用ss :需要查看整体网络连接状况、进行性能分析或在高并发服务器上做统计时,使用ss
  3. 忘记netstat :除非维护旧系统,否则请在你的脑海中将netstat归档,并将它的常用功能映射到sslsof上。

掌握lsof,不仅仅是学会一个新命令,更是对Linux"一切皆文件"哲学的一次深刻体悟。它像一把手术刀,能够精确地切开系统的表皮,让你直视其内部的生命活动。希望通过这篇详尽的报告,你能将lsof从你的"备用工具"提升为"首选利器",在未来的系统管理与排错之路上,更加游刃有余。

相关推荐
A小辣椒20 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒1 天前
TShark:基础知识
linux
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式