使用lsof查看端口占用

0x81 lsof的作用

我们都知道ls命令是Linux发行版系统最常用的命令之一,它用于列出指定目录的文件系统信息,帮助我们快速定位文件。而lsof命令的作用是什么,根据manual的解释,lsof是list open files的意思,它的作用就是列出那些被操作系统进程打开的文件,由于Linux上一切皆文件,我们可以通过这个工具找出占用某个文件的进程。

0x82 react-native的packager启动失败

一年多以前在学习RN的跨平台开发的时候,那个时候RN还是0.2x的版本,现如今都到0.44了依然没有发布正式版,fresco都1.3.0了。当然1.0也就是个版本号没什么实际意义,无非就是开发人员认为bug少到了可以放出一个正式版了而已。React-Native自退出之时受到了很多开发者的青睐,但是它对iOS的支持要远优于Android是事实,当初抱着复习js并进一步学习跨平台开发的想法,也踩了不少的坑(最大的坑就是之前写的demo由于后来有了太多的broken changes,在新版本上直接编不过,一气之下就删掉了工程)。

RN的调试状态是通过一个本地的packager服务推送新的jsbundle到设备并渲染运行的,曾经packager没有使用一个单独的shell起,就出现了packager启动失败的现象,原因就是默认的8081被占用。端口占用其实时很常见的一件事,我们在电脑上跑一个tomcat很有可能就占用了8080,如果你想再起一个使用8080端口的程序,就会提示你端口正在被使用。而packager的8081端口我可以确信时没有其他程序占用的,也就是说是它自己占用了,另一个实例起不来。其实发生这种状况的原因就是我用run-android命令调试RN应用,而这个命令会判断是否启动了packager,如果没有就会启动,但是它可能会判断失误,现在我不清楚是否有这个问题,而我后来都是手动起一个packager,就算出了问题也可以直接关掉重启。

那如果端口被占用了,我们还不知道是谁占用的怎么办?RN的文档也提到了解决办法,一是修改packager端口,这种适合8081是必须被其他程序占用的情况;另一种就是lsof了,命令很简单,输入sudo lsof -n -i4TCP:8081 | grep LISTEN就可以找到占用8081端口的进程,kill掉进程id即可。

0x83 lsof展示的信息

lsof的参数非常的多,通用文档man其实也说的很明白,这个命令在某些时候有奇效的根本原因就是“一切皆文件”的哲学,我不会照搬文档,主要记录一下一些常用的参数和方法,巩固自己的知识。

首先直接执行lsof你就能看到很多有用的信息,参数的作用通常是一些过滤条件:

lsof关于自身的结果

表头的每一列分别表示命令、进程id、线程id、用户、文件标识符、文件类型、设备、偏移量、inode号、文件路径。

前面的很好理解,其中文件标识符主要有cwd(当前工作目录)、rtd(可读文件夹)、mem(内存映射文件)、txt(文本,非普通文本,一般是代码文件),文件类型主要有IPv4/6(ipv4/6)、inet/unix(internet socket/local socket)、BLK(块文件)、CHR(字符文件)、REG(一般文件)、DIR(文件夹)等。

对于文件标识符,程序打开一个文件的时候都会返回一个文件描述符n,这个n就是FD的自增数字,它和权限(rwu:可读可写可读写)共同构成了一般的FD列,0-2表示的是众所周知的标准输入输出和错误,这三个是必然存在的。

0x84 一般用法

  1. 直接使用
    lsof列出所有进程打开的文件

  2. 显示某个用户打开的文件

    • lsof -u user显示user执行的程序打开的文件
    • lsof -u ^user显示除user外的用户打开的文件
  3. 显示某个目录下被打开的文件
    lsof +d/D DIR显示当前/递归目录下打开的文件

  4. 常用方法
    lsof -i[46] [protocol][@hostname|hostaddr][:service|port]按规则显示打开的文件,例如lsof -n -i4 :22表示查看22端口在IPv4下的使用情况

有了第4种用法,基本上已经能解决大部分问题了,我们还可以使用强大的管道完成过滤操作,lsof甚至可以用于恢复文件,就不在这里展开了。