Contents

有效地测试一个端口是否在Linux中打开

1. 概述

在本教程中,我们将研究检查网络端口是否为 Linux 中的连接打开的方法。我们将仔细研究一些可用于此目的的 Bash 实用程序。我们还将对提供的方法的性能进行基准测试,以实现高效的解决方案。

2. 使用netstat命令

Linux 中的netstat 命令行实用程序打印许多网络协议和接口的网络统计信息。我们可以使用它来调查网络套接字并测试 Linux 中网络端口的状态。首先,让我们验证netstat命令的默认输出:

$ netstat | head
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 localhost:34702         localhost:8684          ESTABLISHED
tcp        0      0 localhost:5747          localhost:55488         ESTABLISHED
tcp        0      0 localhost:5161          localhost:44858         ESTABLISHED
tcp        0      0 localhost:8580          localhost:42432         ESTABLISHED
tcp        0      0 localhost:54090         localhost:3852          ESTABLISHED
tcp        0      0 localhost:8186          localhost:52896         ESTABLISHED
tcp        0      0 localhost:7367          localhost:43282         ESTABLISHED
tcp        0      0 localhost:4441          localhost:35762         ESTABLISHED
$

在此输出中,在“ Local Address ”和“ Foreign Address ”列下,**端口号列在冒号“ : ”**之后。网络地址的状态(IP 和端口的组合)列在“State”列中。

让我们修改我们的命令来检查特定端口的状态:

$ netstat -nap | grep ":8001"
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN      19135/nc
tcp        0      0 127.0.0.1:8001          127.0.0.1:55368         ESTABLISHED 19135/nc
tcp        0      0 127.0.0.1:55368         127.0.0.1:8001          ESTABLISHED 19138/nc

在这里,我们使用grep 命令检查端口“ 8001 ”的状态。

请注意,我们使用*-n选项强制它打印数字地址,而不是尝试确定主机名。–a选项允许我们打印所有监听套接字以及非监听套接字。-p*选项用于打印此套接字所属进程的 PID 。

当端口处于LISTEN模式时,它为连接打开。因此,让我们用grep查找LISTEN。我们还将使用time 命令查看命令的执行时间:

$ time (netstat -nap | grep ":8001" | grep LISTEN)
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN      19135/nc
real    0m0.471s
user    0m0.199s
sys     0m0.302s

使用上述命令验证端口状态大约需要半秒(0.471 秒)。让我们稍微调整一下命令选项并重新评估执行时间:

$ time (netstat -nl | grep ":8001")
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN
real    0m0.072s
user    0m0.039s
sys     0m0.041s
$

伟大的!我们能够将执行时间从0.471 秒降低到0.072秒。在这里,我们使用-l选项仅列出处于LISTEN模式的套接字。在之前的方法中,netstat列出了所有的套接字,我们使用grep命令在LISTEN*模式下过滤套接字,这会导致额外的开销*。

我们还从命令中删除了*-p选项,因为在这里获取相应进程的PID*并没有多大价值。

让我们也验证一个否定的测试用例:

$ time (netstat -ne | grep ":10001" ; echo $?)
1
real    0m0.088s
user    0m0.079s
sys     0m0.022s
$

在这里,正如预期的那样,netstat没有给出任何输出,而*$?* 由于端口10001未对连接开放,因此也具有非零值。

3. 使用ss命令

ss 是一个用于转储套接字统计信息的 Linux 实用程序。我们来看看它的默认输出:

$ ss | head -10
Netid  State  Recv-Q  Send-Q    Local Address:Port                 Peer Address:Port                                        Process
tcp    ESTAB  0       0             127.0.0.1:34702                   127.0.0.1:8684
tcp    ESTAB  0       0             127.0.0.1:5747                    127.0.0.1:55488
tcp    ESTAB  0       0             127.0.0.1:5161                    127.0.0.1:44858
tcp    ESTAB  0       0             127.0.0.1:8580                    127.0.0.1:42432
tcp    ESTAB  0       0             127.0.0.1:54090                   127.0.0.1:3852
tcp    ESTAB  0       0             127.0.0.1:8186                    127.0.0.1:52896
tcp    ESTAB  0       0             127.0.0.1:7367                    127.0.0.1:43282
tcp    ESTAB  0       0             127.0.0.1:4441                    127.0.0.1:35762
tcp    ESTAB  0       0             127.0.0.1:7024                    127.0.0.1:57206

请注意,该实用程序的输出类似于netstat输出。有趣的是,这个实用程序的参数选项也类似于netstat命令。让我们使用-l选项验证输出以仅列出LISTEN*模式下的套接字:*

$ time (ss -nl | grep ":8001")
tcp   LISTEN 0      1                     0.0.0.0:8001             0.0.0.0:*
real    0m0.029s
user    0m0.039s
sys     0m0.000s

netstat相比,此实用程序更快。使用此实用程序,我们能够将时间进一步减少到0.029 秒,而执行时间为0.072

4. 使用lsof命令

我们还可以使用带有*-i*选项的lsof 实用程序来验证端口是否已打开以进行连接:

$ lsof -i:8001
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      19135 shubh    3u  IPv4 326527      0t0  TCP *:8001 (LISTEN)
nc      19135 shubh    4u  IPv4 326528      0t0  TCP localhost:8001->localhost:55368 (ESTABLISHED)
nc      19138 shubh    3u  IPv4 326555      0t0  TCP localhost:55368->localhost:8001 (ESTABLISHED)
$

由于我们只对LISTEN模式感兴趣,让我们在命令中添加一个grep过滤器:

$ time (lsof -i:8001 | grep "LISTEN")
nc      19135 shubh    3u  IPv4 326527      0t0  TCP *:8001 (LISTEN)
real    0m0.625s
user    0m0.133s
sys     0m0.492s
$

值得注意的是,显示相关信息比netstatss实用程序需要更多时间。在这里,我们使用grep命令显式过滤了输出。让我们也尝试使用内置标志-iTCP -sTCP:LISTENLISTEN*模式*列出网络文件:

$ time (lsof -iTCP:8001 -sTCP:LISTEN)
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      19135 shubh    3u  IPv4 326527      0t0  TCP *:8001 (LISTEN)
real    0m0.496s
user    0m0.090s
sys     0m0.407s

尽管我们能够降低执行时间,但与netstatss实用程序相比,它仍然相当大。