网络连通性验证,是服务器环境搭建的重要任务之一。检查目标机器的服务端口是否可连通,常见的端口检测方法有 telnet、nc 等方法,并提供了一份批量检测脚本,整理如下。

telnet

telnet 是最普遍的方法。非常简单,语法如下:

telnet $host $port

输出如下,表示端口联通(通过ctl+]退出):

maoshuai@ms:/tmp$ telnet 127.0.0.1 22
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

如下,表示端口不通:

maoshuai@ms:/tmp$ telnet 127.0.0.1 222
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused

nc

telnet 是交互式的,适合单次手工检测,对于批量检测,利用nc更为方便。基本用法如下:

nc -z $host $port

然后检测上述命令的exit code,为0表示可联通,否则表示不联通:

maoshuai@ms:/tmp$ nc -z 127.0.0.1 22
maoshuai@ms:/tmp$ echo $?
0
maoshuai@ms:/tmp$ nc -z 127.0.0.1 222
maoshuai@ms:/tmp$ echo $?
1

假如需要检测一批IP下的端口是否联通,可以用下面的脚本:

#!/bin/bash
# checking network connectivity

# IPs and ports to check
# Ignore blank lines and treat hash sign as comments
# comments will be kept as a comment of result
IP_PORT="
# local host 
127.0.0.1 22
127.0.0.1 21
# well known sites
www.google.com 80
www.baidu.com 80
"

# checking
echo "$IP_PORT" | grep -Ev "^$" |
while read line;do
  # simply print comment line
  echo "$line" | grep -qE "^#"
  if [ $? -eq 0 ];then
	  echo "$line"
	  continue
  fi

  # normal line with ip and port
  connectFlag="DOWN"
  nc -z -w 1 $line
  if [ $? -eq 0 ];then
	  connectFlag="UP"
  fi

  printf "%-20s %5s %5s\n" $line $connectFlag
done

上述脚本,可能输出如下,最后一列UP表示联通,否则DOWN为不通:

# local host
127.0.0.1               22    UP
127.0.0.1               21  DOWN
# well known sites
www.google.com          80    UP
www.baidu.com           80    UP

脚本中增加了-w选项,用于控制最大探测超时时间为1秒。

当然,也可以通过-v选项直接输出探测信息,适合单次手工查验,:

maoshuai@ms:/tmp$ nc -zv 127.0.0.1 22
Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!
maoshuai@ms:/tmp$ nc -zv 127.0.0.1 222
nc: connect to 127.0.0.1 port 222 (tcp) failed: Connection refused

通过写入设备文件

由于Linux里,一切都是文件,网络连接也对应一个文件。因此可以通过直接写入文件判断端口是否联通。

这种方法有点awkward,但是最兼容的方法。如果所在的服务器中没有安装nc甚至telnet命令(比如某些docker容器中),用法如下:

echo > /dev/tcp/$host/$port

判断上述命令的退出码:

maoshuai@ms:/dev$ echo > /dev/tcp/127.0.0.1/22
maoshuai@ms:/dev$ echo $?
0
maoshuai@ms:/dev$ echo > /dev/tcp/127.0.0.1/222
bash: connect: Connection refused
bash: /dev/tcp/127.0.0.1/222: Connection refused
maoshuai@ms:/dev$ echo $?
1

当然,也可以通过脚本,批量检测:

#!/bin/bash
# checking network connectivity

# IPs and ports to check
# Ignore blank lines and treat hash sign as comments
# comments will be kept as a comment of result
IP_PORT="
# local host 
127.0.0.1 22
127.0.0.1 21

# well known sites
www.google.com 80
www.baidu.com 80
"

# checking
echo "$IP_PORT" | grep -Ev "^$" |
while read line;do
  # simply print comment line
  echo "$line" | grep -qE "^#"
  if [ $? -eq 0 ];then
	  echo "$line"
	  continue
  fi

  # normal line with ip and port
  connectFlag="DOWN"
  ip=$(echo $line | awk '{print $1}')
  port=$(echo $line | awk '{print $2}')
  (echo > /dev/tcp/$ip/$port) >/dev/null 2>&1
  if [ $? -eq 0 ];then
    connectFlag="UP"
  fi

  printf "%-20s %5s %5s\n" $line $connectFlag
done

输出结果和第一个方法一样,但有个地方注意,必须用bash执行写入。

在服务部署前检测端口

有些情况,我们需要在服务部署前检测该服务的端口是否可访问。问题是此时这个端口并没有被监听,直接检测的结果自然是不通,我们需要排除,这不是因为网络本身不通(比如有防火墙)造成的。

一种办法是,在目标机器的该端口部署一个简单的监听,而nc命令恰巧可以完成,参数-l表示监听,后面跟着监听的端口:

nc -l 22

然后我们再次运行之前的脚本,会发现22端口显示为UP了。

参考文档

-------------------------

本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可。转载请注明来源:https://wiki.imshuai.com/remoe-server-port-checking.html 欢迎指正或在下方评论。