如果远程TCP端口已打开,则从shell脚本进行testing
我正在寻找一种快速而简单的方法,用于从Shell脚本中正确testing远程服务器上是否打开给定的TCP端口。
我已经设法做到这一点与telnet命令,它可以正常工作,当端口打开,但似乎并没有超时,当它不是,只是挂在那里…
这是一个示例:
l_TELNET=`echo "quit" | telnet $SERVER $PORT | grep "Escape character is"` if [ "$?" -ne 0 ]; then echo "Connection to $SERVER on port $PORT failed" exit 1 else echo "Connection to $SERVER on port $PORT succeeded" exit 0 fi
我要么需要更好的方法,要么强制telnet超时,如果它不能在8秒内连接,并返回一些我可以在壳牌(返回代码,或在标准输出string)捕获的东西。
我知道Perl方法,它使用IO :: Socket :: INET模块,编写了一个testing端口的成功脚本,但是如果可能的话,宁愿避免使用Perl。
注意:这是我的服务器正在运行(我需要从这里运行)
SunOS 5.10 Generic_139556-08 i86pc i386 i86pc
正如B. Rhodes所指出的那样, nc
会做这项工作。 更紧凑的方式来使用它:
nc -z <host> <port>
这样nc
只会检查端口是否打开,成功时退出0,失败时退出1。
快速交互式检查(5秒超时):
nc -z -v -w5 <host> <port>
使用-z
和-w TIMEOUT
选项很容易,但不是所有的系统都安装了nc
。 如果你有最新版本的bash,这将工作:
# Connection successful: $ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/google.com/80' $ echo $? 0 # Connection failure prior to the timeout $ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/sfsfdfdff.com/80' bash: sfsfdfdff.com: Name or service not known bash: /dev/tcp/sfsfdfdff.com/80: Invalid argument $ echo $? 1 # Connection not established by the timeout $ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/google.com/81' $ echo $? 124
这里发生的事情是, timeout
将运行子命令,如果在指定的超时(上例中为1秒)内没有退出,则将其终止。 在这种情况下, bash
是子命令,并使用其特殊的/ dev / tcp处理来尝试打开指定的服务器和端口的连接。 如果bash
可以在超时时间内打开连接, cat
会立即closures它(因为它是从/dev/null
读取的),并以状态码0
退出,然后通过bash
传播,然后timeout
。 如果bash
在指定的超时之前获得连接失败,那么bash
将以退出代码1退出,该退出代码也将返回。 如果bash无法build立连接,并且指定的超时过期,则timeout
将终止bash
并退出,状态为124。
TOC:
- 使用bash和
timeout
- 命令
- 例子
- 使用
nc
- 命令
- RHEL 6(nc-1.84)
- 安装
- 例子
- RHEL 7(nmap-ncat-6.40)
- 安装
- 例子
- 备注
使用bash和timeout
:
请注意, timeout
应该在RHEL 6+中出现,或者可以在GNU coreutils 8.22中find。 在MacOS上,使用brew install coreutils
进行brew install coreutils
并将其用作gtimeout
。
命令:
$ timeout $TIMEOUT_SECONDS bash -c "</dev/tcp/${HOST}/${PORT}"; echo $?
如果参数化主机和端口,请确保像上面那样将它们指定为${HOST}
和${PORT}
。 不要仅仅把它们指定为$HOST
和$PORT
,也就是说不用大括号。 在这种情况下不起作用。
例:
成功:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/80"; echo $? 0
失败:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $? 124
如果你必须保存bash
的退出状态,
$ timeout --preserve-status 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $? 143
使用nc
:
请注意,在RHEL 7上安装了不兼容的nc
版本。
命令:
请注意,下面的命令是独一无二的,因为它对于RHEL 6和7都是相同的。只是安装和输出是不同的。
$ nc -w $TIMEOUT_SECONDS -v $HOST $PORT </dev/null; echo $?
RHEL 6(nc-1.84):
安装:
$ sudo yum install nc
例子:
成功:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $? Connection to canyouseeme.org 80 port [tcp/http] succeeded! 0
失败:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $? nc: connect to canyouseeme.org port 81 (tcp) timed out: Operation now in progress 1
如果主机名映射到多个IP,则上述失败命令将循环遍历许多或全部。 例如:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $? nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress 1
RHEL 7(nmap-ncat-6.40):
安装:
$ sudo yum install nmap-ncat
例子:
成功:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $? Ncat: Version 6.40 ( http://nmap.org/ncat ) Ncat: Connected to 52.202.215.126:80. Ncat: 0 bytes sent, 0 bytes received in 0.22 seconds. 0
失败:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $? Ncat: Version 6.40 ( http://nmap.org/ncat ) Ncat: Connection timed out. 1
如果主机名映射到多个IP,则上述失败命令将循环遍历许多或全部。 例如:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $? Ncat: Version 6.40 ( http://nmap.org/ncat ) Ncat: Connection to 104.43.195.251 failed: Connection timed out. Ncat: Trying next address... Ncat: Connection to 23.100.122.175 failed: Connection timed out. Ncat: Trying next address... Ncat: Connection to 23.96.52.53 failed: Connection timed out. Ncat: Trying next address... Ncat: Connection to 191.239.213.197 failed: Connection timed out. Ncat: Trying next address... Ncat: Connection timed out. 1
备注:
-v
(– --verbose
)参数和echo $?
命令当然仅用于说明。
使用netcat
你可以检查一个端口是否是这样打开的:
nc my.example.com 80 < /dev/null
如果TCP端口被打开,则nc
的返回值将是成功的,如果不能进行TCP连接则返回失败(通常返回码1)。
在Bash中使用TCP / UDP连接的伪设备文件非常简单。 这是脚本:
#!/usr/bin/env bash SERVER=example.com PORT=80 </dev/tcp/$SERVER/$PORT if [ "$?" -ne 0 ]; then echo "Connection to $SERVER on port $PORT failed" exit 1 else echo "Connection to $SERVER on port $PORT succeeded" exit 0 fi
testing:
$ ./test.sh Connection to example.com on port 80 succeeded
这里是一行(Bash语法):
</dev/tcp/localhost/11211 && echo Port open. || echo Port closed.
请注意,有些服务器可以防止SYN洪水攻击的防火墙,所以您可能会遇到TCP连接超时(〜75secs)。 要解决超时问题,请尝试:
timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.
请参阅: 如何减lessTCP连接()系统调用超时?
虽然这是一个古老的问题,但我刚刚讨论过它的一个变种,但是这里没有一个解决scheme适用,所以我find了另一个解决scheme,并将其添加到后代。 是的,我知道OP说他们意识到这个select,并不适合他们,但是对于以后的任何人来说,这可能是有用的。
在我的情况下,我想testing一个docker
构build的本地apt-cacher-ng
服务的可用性。 这意味着在testing之前绝对不能安装任何东西。 没有nc
, nmap
, expect
, telnet
或者python
。 然而, perl
和核心库一样,所以我使用了这个:
perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))'
如果您使用ksh或bash,则它们都使用/ dev / tcp / IP / PORT构造支持到/来自套接字的IOredirect。 在这个Korn shell的例子中,我正在从套接字redirectno-op的( : )std-in:
W$ python -m SimpleHTTPServer & [1] 16833 Serving HTTP on 0.0.0.0 port 8000 ... W$ : </dev/tcp/127.0.0.1/8000
如果套接字未打开,shell将打印一个错误:
W$ : </dev/tcp/127.0.0.1/8001 ksh: /dev/tcp/127.0.0.1/8001: cannot open [Connection refused]
因此,您可以在if条件下将其用作testing :
SERVER=127.0.0.1 PORT=8000 if (: < /dev/tcp/$SERVER/$PORT) 2>/dev/null then print succeeded else print failed fi
无操作是在一个子shell中,所以如果std-inredirect失败,我可以把std-err扔掉。
我经常使用/ dev / tcp通过HTTP检查资源的可用性:
W$ print arghhh > grr.html W$ python -m SimpleHTTPServer & [1] 16863 Serving HTTP on 0.0.0.0 port 8000 ... W$ (print -u9 'GET /grr.html HTTP/1.0\n';cat <&9) 9<>/dev/tcp/127.0.0.1/8000 HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/2.6.1 Date: Thu, 14 Feb 2013 12:56:29 GMT Content-type: text/html Content-Length: 7 Last-Modified: Thu, 14 Feb 2013 12:55:44 GMT arghhh W$
这一行打开文件描述符9,用于读写套接字,将HTTP GET打印到套接字并使用cat
从套接字中读取。
我需要一个更灵活的解决scheme来处理多个git存储库,所以我根据1和2编写了以下sh代码。 您可以使用您的服务器地址而不是gitlab.com和您的端口replace22。
SERVER=gitlab.com PORT=22 `nc -z -v -w5 $SERVER $PORT` result1=$? #Do whatever you want if [ "$result1" != 0 ]; then echo 'port 22 is closed' else echo 'port 22 is open' fi
我猜猜答案已经太晚了,这可能不是一个好的答案,但是你在这里…
把它放在一个while循环里面,有一个定时器就可以了。 我更像是一个比Solaris更像Perl的人,但是根据你使用的shell,你应该能够做到这样的事情:
TIME = 'date +%s' + 15 while TIME != `date +%s' do whatever
然后在while循环中添加一个标志,这样如果在完成之前超时,可以引用超时作为失败的原因。
我怀疑,telnet也有一个超时切换,但只是我的头顶,我认为上述将工作。
如果您想使用nc
但是没有支持-z
的版本,请尝试使用--send-only
:
nc --send-only <IP> <PORT> </dev/null
并超时:
nc -w 1 --send-only <IP> <PORT> </dev/null
没有DNS查询,如果它是一个IP:
nc -n -w 1 --send-only <IP> <PORT> </dev/null
它返回的代码为-z
基于它是否可以连接。
在curl,telnet,nc o nmap等工具不可用的情况下,您仍然可以使用wget
if [[ $(wget -q -t 1 --spider --dns-timeout 3 --connect-timeout 10 host:port; echo $?) -eq 0 ]]; then echo "OK"; else echo "FAIL"; fi
Netcat或Nmap呢?
我需要在cron运行的短脚本,并没有输出。 我用nmap解决了我的麻烦
open=`nmap -p $PORT $SERVER | grep "$PORT" | grep open` if [ -z "$open" ]; then echo "Connection to $SERVER on port $PORT failed" exit 1 else echo "Connection to $SERVER on port $PORT succeeded" exit 0 fi
运行它你应该安装nmap,因为它不是默认的安装包。
这在后台使用telnet,似乎在mac / linux上正常工作。 它不使用netcat,因为linux / mac上版本之间的差异,这与默认的mac安装。
例:
$ is_port_open.sh 80 google.com OPEN $ is_port_open.sh 8080 google.com CLOSED
is_port_open.sh
PORT=$1 HOST=$2 TIMEOUT_IN_SEC=${3:-1} VALUE_IF_OPEN=${4:-"OPEN"} VALUE_IF_CLOSED=${5:-"CLOSED"} function eztern() { if [ "$1" == "$2" ] then echo $3 else echo $4 fi } # cross platform timeout util to support mac mostly # https://gist.github.com/jaytaylor/6527607 function eztimeout() { perl -e 'alarm shift; exec @ARGV' "$@"; } function testPort() { OPTS="" # find out if port is open using telnet # by saving telnet output to temporary file # and looking for "Escape character" response # from telnet FILENAME="/tmp/__port_check_$(uuidgen)" RESULT=$(eztimeout $TIMEOUT_IN_SEC telnet $HOST $PORT &> $FILENAME; cat $FILENAME | tail -n1) rm -f $FILENAME; SUCCESS=$(eztern "$RESULT" "Escape character is '^]'." "$VALUE_IF_OPEN" "$VALUE_IF_CLOSED") echo "$SUCCESS" } testPort
使用bash检查端口
例
$ ./test_port_bash.sh 192.168.7.7 22
端口22打开
码
HOST=$1 PORT=$2 exec 3> /dev/tcp/${HOST}/${PORT} if [ $? -eq 0 ];then echo "the port $2 is open";else echo "the port $2 is closed";fi
nmap-ncat来testing尚未使用的本地端口
availabletobindon() { port="$1" nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q 'Idle timeout expired' return "$?" }
答案与Expect有关。 我们写了一个简单的脚本,在我们需要的端口上发送一个telnet,超时时间为8秒。 还有很多例子可以select。
我们基于我们的这个职位: http : //www.unix.com/shell-programming-scripting/146568-expect-telnet-testing-tacacs-cisco.html