我正在寻找一种快速而简单的方法,用于在Shell脚本内部正确测试远程服务器上是否打开给定的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
我要么需要一个更好的方法,或者如果它在8秒内没有连接就强制telnet超时,并返回我可以在Shell中捕获的东西(返回代码或stdout中的字符串)。 / p>
我知道Perl方法,它使用IO :: Socket :: INET模块并编写了一个测试端口的成功脚本,但是如果可能的话,我宁愿避免使用Perl。
注意:这就是我的服务器正在运行的地方(我需要从中运行它)
SunOS 5.10 Generic_139556-08 i86pc i386 i86pc
答案 0 :(得分:421)
正如B. Rhodes指出的,nc
将完成这项工作。一种更紧凑的使用方式:
nc -z <host> <port>
那样nc
只检查端口是否打开,成功时退出0,失败时退出1。
进行快速互动检查(超时5秒):
nc -z -v -w5 <host> <port>
答案 1 :(得分:129)
对-z
的{{1}}和-w TIMEOUT
选项很容易,但并非所有系统都安装了nc
。如果您有最新版本的bash,这将有效:
nc
这里发生的是# 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
将运行子命令并在它未在指定超时内退出时杀死它(在上例中为1秒)。在这种情况下,timeout
是子命令,并使用其特殊的/dev/tcp handling来尝试打开与指定的服务器和端口的连接。如果bash
可以在超时内打开连接,bash
将立即关闭它(因为它正在从cat
读取)并退出状态代码/dev/null
,这将传播通过0
然后bash
。如果timeout
在指定的超时之前导致连接失败,则bash
将退出,退出代码为1 bash
也将返回。如果bash无法建立连接且指定的超时时间到期,则timeout
将终止timeout
并退出状态为124。
答案 2 :(得分:96)
timeout
nc
timeout
:请注意,timeout
应与RHEL 6+一起出现,或者在GNU coreutils 8.22中找到。在MacOS上,使用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 $?
$ 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,则上述失败命令将循环显示其中的多个或所有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
$ 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,则上述失败命令将循环显示其中的多个或所有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 $?
命令当然只是为了说明。
答案 3 :(得分:49)
使用netcat
,您可以检查端口是否像这样打开:
nc my.example.com 80 < /dev/null
如果TCP端口被打开,nc
的返回值将成功,如果无法建立TCP连接,则返回失败(通常是返回码1)。
尝试此操作时,某些版本的nc
会挂起,因为即使在收到/dev/null
的文件结尾后,它们也不会关闭其套接字的一半。在我自己的Ubuntu笔记本电脑(18.04)上,我安装的netcat-openbsd
版本的netcat提供了一种解决方法:-N
选项是获得即时结果所必需的:
nc -N my.example.com 80 < /dev/null
答案 4 :(得分:25)
在Bash中使用pseudo-device files进行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
测试:
$ ./test.sh
Connection to example.com on port 80 succeeded
这是一行(Bash语法):
</dev/tcp/localhost/11211 && echo Port open. || echo Port closed.
请注意,某些服务器可以防止SYN Flood攻击,因此您可能会遇到TCP连接超时(~75秒)。要解决超时问题,请尝试:
timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.
答案 5 :(得分:10)
如果您使用 ksh 或 bash ,他们都支持使用 / dev / tcp / IP / PORT 来自套接字的IO重定向强>构造。在这个 Korn shell 示例中,我正在从套接字重定向no-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 条件中将其用作测试:
SERVER=127.0.0.1 PORT=8000
if (: < /dev/tcp/$SERVER/$PORT) 2>/dev/null
then
print succeeded
else
print failed
fi
no-op在子shell中,所以如果std-in重定向失败,我可以抛弃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 打印到套接字并使用 {{1} 从套接字读取。
答案 6 :(得分:10)
我需要一个更灵活的解决方案来处理多个git存储库,因此我根据1和2编写了以下sh代码。您可以使用您的服务器地址代替gitlab.com,并将您的端口替换为22。
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
答案 7 :(得分:9)
虽然一个老问题,我刚刚处理了它的一个变体,但这里没有一个解决方案是适用的,所以我找到了另一个,并为后代添加它。是的,我知道OP说他们知道这个选项而且它不适合他们,但是对于之后跟随它的人来说它可能是有用的。
在我的情况下,我想测试apt-cacher-ng
版本中本地docker
服务的可用性。这意味着在测试之前绝对不能安装任何东西。否nc
,nmap
,expect
,telnet
或python
。然而,perl
和核心库一起存在,所以我使用了这个:
perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))'
答案 8 :(得分:6)
在某些情况下,如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
答案 9 :(得分:4)
如果您想使用def compute_av_precision(match_list):
n = len(match_list)
tp_counter = 0
cumulate_precision = 0
for i in range(0,n):
if match_list[i] == True:
tp_counter += 1
cumulate_precision += (float(tp_counter)/float(i+1))
if tp_counter != 0:
av_precision = cumulate_precision/float(tp_counter)
return av_precision
return 0
但没有支持nc
的版本,请尝试使用-z
:
--send-only
并且超时:
nc --send-only <IP> <PORT> </dev/null
如果是IP,则不进行DNS查找:
nc -w 1 --send-only <IP> <PORT> </dev/null
根据是否可以连接,它将代码作为nc -n -w 1 --send-only <IP> <PORT> </dev/null
返回。
答案 10 :(得分:3)
$ ./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
答案 11 :(得分:1)
我猜这个答案已经太迟了,这可能不是一个好的,但是你去了......
把它放在一个带有定时器的while循环中怎么样?我不仅仅是Solaris的Perl人,但根据你使用的shell,你应该可以做类似的事情:
TIME = 'date +%s' + 15
while TIME != `date +%s'
do whatever
然后只需在while循环中添加一个标志,这样如果它在完成之前超时,你可以引用超时作为失败的原因。
我怀疑telnet也有一个超时开关,但是我认为上面的内容是可行的。
答案 12 :(得分:1)
我需要在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,因为它不是默认安装包。
答案 13 :(得分:0)
这在幕后使用telnet,似乎在mac / linux上运行良好。它不使用netcat,因为linux / mac上的版本之间存在差异,这适用于默认的mac安装。
$ is_port_open.sh 80 google.com
OPEN
$ is_port_open.sh 8080 google.com
CLOSED
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
答案 14 :(得分:0)
在最高投票答案的基础上,这里有一个等待两个端口打开的功能,也有一个超时。注意两个打开的端口,8890和1111,以及max_attempts(每秒1个)。
function wait_for_server_to_boot()
{
echo "Waiting for server to boot up..."
attempts=0
max_attempts=30
while ( nc 127.0.0.1 8890 < /dev/null || nc 127.0.0.1 1111 < /dev/null ) && [[ $attempts < $max_attempts ]] ; do
attempts=$((attempts+1))
sleep 1;
echo "waiting... (${attempts}/${max_attempts})"
done
}
答案 15 :(得分:-1)
availabletobindon() {
port="$1"
nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q 'Idle timeout expired'
return "$?"
}