CppGuide社区 CppGuide社区
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
  • 第1章高频C++11重难点知识解析

  • 第2章Linux GDB高级调试指南

  • 第3章C++多线程编程从入门到进阶

  • 第4章C++网络编程重难点解析

  • 第5章网络通信故障排查常用命令

    • 5.1 ifconfig
    • 5.2 ping
    • 5.3 telnet
    • 5.4 netstat
    • 5.5 lsof
      • 5.6 nc
      • 5.7 curl
      • 5.8 tcpdump
    • 第6章高性能网络通信协议设计精要

    • 第7章高性能服务结构设计

    • 第8章Redis 网络通信模块源码分析

    • 第9章后端服务重要模块设计探索

    • C++后端开发进阶
    • 第5章网络通信故障排查常用命令
    zhangxf
    2023-04-05
    目录

    5.5 lsof

    lsof 命令是 Linux 系统的扩展工具,它的含义是 list opened filedesciptor (列出已经打开的文件描述符),在 Linux 系统中,所有的与资源句柄相关的东西都可以统一抽象成文件描述符(filedescriptor,简称 fd)。一个文件句柄是一个 fd,一个 socket 对象也可以称之为 fd 等等。

    # 5.5.1 lsof 命令的基本用法

    默认情况下,系统是不存在这个命令的,你需要安装一下,使用如下命令安装:

    yum install lsof
    
    1

    我们来看一下这个命令的使用效果:

    COMMAND     PID   TID    USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
    systemd       1          root  cwd       DIR              202,1      4096          2 /
    nscd        453   469    nscd    8u  netlink                          0t0      11017 ROUTE
    nscd        453   470    nscd  cwd       DIR              202,1      4096          2 /
    nscd        453   470    nscd  rtd       DIR              202,1      4096          2 /
    nscd        453   470    nscd  txt       REG              202,1    180272     146455 /usr/sbin/nscd
    nscd        453   470    nscd  mem       REG              202,1    217032     401548 /var/db/nscd/hosts
    nscd        453   470    nscd  mem       REG              202,1     90664     132818 /usr/lib64/libz.so.1.2.7
    nscd        453   470    nscd  mem       REG              202,1     68192     133155 /usr/lib64/libbz2.so.1.0.6
    nscd        453   470    nscd  mem       REG              202,1    153192     133002 /usr/lib64/liblzma.so.5.0.99
    nscd        453   470    nscd  mem       REG              202,1     91496     133088 
    nscd        453   471    nscd    5u  a_inode                0,9         0       4796 [eventpoll]
    nscd        453   471    nscd    6r      REG              202,1    217032     401548 /var/db/nscd/hosts
    nscd        453   471    nscd    7u     unix 0xffff880037497440       0t0      11015 /var/run/nscd/socket
    nscd        453   471    nscd    8u  netlink                          0t0      11017 ROUTE
    imgserver   611       zhangyl  cwd       DIR              202,1      4096    1059054 /home/zhangyl/flamingoserver
    imgserver   611       zhangyl  rtd       DIR              202,1      4096          2 /
    imgserver   611       zhangyl  txt       REG              202,1   4788917    1057044 /home/zhangyl/flamingoserver/imgserver
    imgserver   611       zhangyl   24u  a_inode                0,9         0       4796 [eventfd]
    imgserver   611       zhangyl   25u     IPv4           55707643       0t0        TCP *:commtact-http (LISTEN)
    imgserver   611       zhangyl   26r      CHR                1,3       0t0       4800 /dev/null
    imgserver   611   613 zhangyl   32w      REG              202,1    131072    2754609 /home/zhangyl/flamingoserver/imgcache/258bfb8945288a117d98d440986d7a03
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    结果显示中列出了各个进程打开的各种 fd 类型,对于 Uinx Socket,lsof 命令会显示出其详细的路径,打开的文件 fd 亦是如此。

    使用 lsof 命令有三点需要注意:

    • 默认情况下,lsof 的输出比较多,我们可以使用 grep 命令过滤我们想要查看的进程打开的 fd 信息,如:

      lsof -i | grep myapp
      
      1

      或者使用 lsof -p pid 也能过滤出指定的进程打开的 fd 信息:

      [root@iZ238vnojlyZ ~]# lsof -p 26621
      COMMAND     PID    USER   FD      TYPE   DEVICE SIZE/OFF    NODE NAME
      chatserve 26621 zhangyl  cwd       DIR    202,1     4096 1059054 /home/zhangyl/flamingoserver
      chatserve 26621 zhangyl  rtd       DIR    202,1     4096       2 /
      chatserve 26621 zhangyl  txt       REG    202,1  8027035 1051942 /home/zhangyl/flamingoserver/chatserver
      chatserve 26621 zhangyl  mem       REG    202,1    61928  141417 /usr/lib64/libnss_files-2.17.so
      chatserve 26621 zhangyl  mem       REG    202,1    44096  143235 /usr/lib64/librt-2.17.so
      chatserve 26621 zhangyl  mem       REG    202,1    19520  137064 /usr/lib64/libdl-2.17.so
      chatserve 26621 zhangyl  mem       REG    202,1  2112384  132824 /usr/lib64/libc-2.17.so
      chatserve 26621 zhangyl  mem       REG    202,1   142304  132850 /usr/lib64/libpthread-2.17.so
      chatserve 26621 zhangyl  mem       REG    202,1    88720  135291 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
      chatserve 26621 zhangyl  mem       REG    202,1  1141560  137077 /usr/lib64/libm-2.17.so
      chatserve 26621 zhangyl  mem       REG    202,1   999944  140059 /usr/lib64/libstdc++.so.6.0.19
      chatserve 26621 zhangyl  mem       REG    202,1  9879756  269001 /usr/lib64/mysql/libmysqlclient.so.20.3.4
      chatserve 26621 zhangyl  mem       REG    202,1   164440  133622 /usr/lib64/ld-2.17.so
      chatserve 26621 zhangyl    0u      CHR      1,3      0t0    4800 /dev/null
      chatserve 26621 zhangyl    1u      CHR      1,3      0t0    4800 /dev/null
      chatserve 26621 zhangyl    2u      CHR      1,3      0t0    4800 /dev/null
      chatserve 26621 zhangyl    3u  a_inode      0,9        0    4796 [eventpoll]
      chatserve 26621 zhangyl    4u  a_inode      0,9        0    4796 [timerfd]
      chatserve 26621 zhangyl    5u  a_inode      0,9        0    4796 [eventfd]
      chatserve 26621 zhangyl    7u  a_inode      0,9        0    4796 [eventpoll]
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
    • lsof 命令只能查看到当前用户有权限查看到的进程 fd 信息,对于其没有权限的进程,最右边一列会显示 “Permission denied”。如下所示:

      sshd      26759          root  cwd   unknown                              /proc/26759/cwd (readlink: Permission denied)
      sshd      26759          root  rtd   unknown                              /proc/26759/root (readlink: Permission denied)
      sshd      26759          root  txt   unknown                              /proc/26759/exe (readlink: Permission denied)
      sshd      26759          root NOFD                                        /proc/26759/fd (opendir: Permission denied)
      bash      26761          root  cwd   unknown                              /proc/26761/cwd (readlink: Permission denied)
      bash      26761          root  rtd   unknown                              /proc/26761/root (readlink: Permission denied)
      bash      26761          root  txt   unknown                              /proc/26761/exe (readlink: Permission denied)
      bash      26761          root NOFD                                        /proc/26761/fd (opendir: Permission denied)
      
      1
      2
      3
      4
      5
      6
      7
      8
    • lsof 命令第一栏进程名在显示的时候,默认显示前 n 个字符,这样如果我们需要显示完整的进程名以方便过滤的话,可以使用 +c 选项。用法如下:

      #最左侧的程序名最大显示 15 个字符
      [zhangyl@iZ238vnojlyZ ~]$ lsof +c 15
      
      1
      2

      当然,如果你设置值太大, lsof 便不会采用你设置的最大值,而是使用默认最大值。

    上文也介绍了,socket 也是一种 fd,如果需要仅显示系统的网络连接信息,使用的是 -i 选项即可,这个选项可以形象地显示出系统当前的出入连接情况:

    看到图中的连接方向了吧?

    当然,和 netstat 命令一样,lsof -i 默认也会显示 ip 地址和端口号的别名,我们只要使用 -n 和 -P 选项就能相对应地显示 ip 地址和端口号了,综合起来就是 lsof -Pni:

    # 5.5.2 使用 lsof 命令恢复被删除的文件

    这里再介绍一个利用 lsof 命令恢复被删除的文件的小技巧。下面我们来演示一下,为了避免出现意外造成损失,建议读者在实验之前备份要删除的文件。

    某时某刻,某个日志文件 fileserver.20190814145718.12975.log 被一个叫 fileserver 的程序正使用着。我们可以使用 lsof 命令验证:

    [zhangyl@iZ238vnojlyZ logs]$ lsof | grep fileserve
    
    1

    上图的输出证明 fileserver.20190814145718.12975.log 确实被进程 fileserver 使用,进程 ID 是 12976。

    我们将该日志文件删除:

    [zhangyl@iZ238vnojlyZ logs]$ rm -rf fileserver.20190814145718.12975.log
    
    1

    然后再次使用 lsof 查看一下进程 fileserver 使用该文件的状态信息:

    此时该进程中该文件已经被标记为 deleted 状态了。

    我们进入目录 /proc/pid/fd/ 并使用 ll (ls -l 的别名)命令查看文件状态,这里的 pid 要换成相应进程的 ID,这里就是 12976:

    [zhangyl@iZ238vnojlyZ 12976]$ cd /proc/12976/fd/
    [zhangyl@iZ238vnojlyZ fd]$ ll
    
    1
    2

    此时我们到了被删除的文件:

    标号 6 正好对应我们删除的文件,使用这个标号进行恢复:

    [zhangyl@iZ238vnojlyZ fd]$ cat 6 > /home/zhangyl/flamingoserver/logs/fileserver.20190814145718.12975.log
    
    1

    这样我们的文件就被恢复到 /home/zhangyl/flamingoserver/logs/ 目录处了。

    使用 lsof 命令恢复的文件需要注意两点:

    1. 如果想成功恢复文件,使用文件的进程必须处于存活状态,这里如果 fileserver 已经退出或被杀死,那就无法用这种方式恢复。

    2. 用这种方式恢复的文件,再次用 lsof 命令查看时这个文件的状态仍然是 deleted 状态,也就是说虽然能够手工恢复,但是进程不会再使用这个文件了。对于这里的日志文件,fileserver 继续运行也不会再往这个文件中写入日志了。所以这里恢复文件一般只是用于某些特殊情况下删除一些重要数据文件的应急恢复。

    上次更新: 2025/04/01, 20:53:14
    5.4 netstat
    5.6 nc

    ← 5.4 netstat 5.6 nc→

    最近更新
    01
    第二章 关键字static及其不同用法
    03-27
    02
    第一章 auto与类型推导
    03-27
    03
    第四章 Lambda函数
    03-27
    更多文章>
    Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式