检测远程 TCP 端口是否可连接
2016 年 12 月 16 日当我们在测试某个网站或网络服务是否正常时,首先需要的是查看 TCP 连接是否正常。
连接 TCP 端口常见的状态有:
Name or service not known
。这是域名解析问题。先检查域名是否拼对,域名解析是否正常 (nslookup)。如果连接任何域名都是这个问题,那应该是本地机器的 DNS 设置问题。No route to host
。无法找到服务器。原因可能是多样的,比如本地路由、防火墙问题,也有可能是服务器网络防火墙问题,路由中间任何环节出错都会造成这个结果。总之无法通过路由找到服务器在哪里。Connection refused
。服务器主动拒绝连接。说明服务器端是有响应的,但是可能端口没有打开 (可以用netstat -ntpl
查看监听端口),也有可能是服务器网络防火墙拒绝了连接 (REJECT)。- 连接超时。这种情况连接长时间没有任何反馈,直到超过指定时间。有可能 IP 对应的服务器就不存在或没有运行,也可能是服务器网络防火墙直接将连接丢掉了 (DROP)。
- 连接成功。可以正常连接到服务。
下面介绍测试远程 TCP 端口能否正常连接的一些方法。
Telnet
telnet
命令是比较常用的测试 TCP 端口的方法。
$ telnet github.com 443
Trying 13.250.177.223...
Connected to github.com.
Escape character is '^]'.
显示 Connected to xxx
则说明连接成功。
不过 telnet
是交互式命令,不方便用在 shell 脚本里。
telnet
是需要单独安装的,不是所有系统都会直接预先安装。
Netcat
Netcat
也是需要单独安装,命令为 nc
。
测试连接并退出:
$ nc -z github.com 443
$ echo $?
0
返回 0 意味着连接成功,返回 1 意味着连接失败。
也可以通过 -w
设置超时时间,单位为秒:
$ nc -z -v -w5 github.com 6789
github.com [13.250.177.223] 6789 (radg): Connection timed out
$ echo $?
1
Bash /dev/tcp
/dev/tcp/<host>/<port>
是 bash 内置支持的的虚拟文件,并不是
*nix 系统提供的,其它 shell
也不支持。通过打开这个文件,可以实现 socket 连接。
$ bash -c 'cat < /dev/null > /dev/tcp/github.com/443'
$ echo $?
0
连接成功会返回 0。
通过 timeout
命令设定超时时间:
$ timeout 5 bash -c 'cat < /dev/null > /dev/tcp/github.com/6789'
$ echo $?
124
$ timeout 5 bash -c 'cat < /dev/null > /dev/tcp/unknown-hostname/80'
bash: unknown-hostname: Name or service not known
bash: /dev/tcp/unknown-hostname/80: Invalid argument
$ echo $?
1
如果超时,timeout
程序会 kill bash 命令并返回 124,其它错误返回 1。
编写 socket 程序
我们也可以编写一个简单的程序来测试 TCP 端口。
这里以 Python
为例,使用
socket
模块:
#!/usr/bin/env python
import socket
server = 'github.com'
port = 443
timeout = 5
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
sock.connect((server, port))
print('Connected')
sock.close()
except socket.error as e:
print("Couldn't connect to server:", e)
raise