有效地测试一个端口是否在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
$
值得注意的是,显示相关信息比netstat或ss实用程序需要更多时间。在这里,我们使用grep命令显式过滤了输出。让我们也尝试使用内置标志-iTCP -sTCP:LISTEN以LISTEN*模式*列出网络文件:
$ 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
尽管我们能够降低执行时间,但与netstat和ss实用程序相比,它仍然相当大。