我正在寻找一种快速而简单的方法,用于正确地测试一个给定的TCP端口是否在远程服务器上打开,从Shell脚本中。

我已经设法用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秒内连接,例如,并返回一些我可以在Shell中捕获的东西(返回代码,或stdout中的字符串)。

我知道Perl方法,它使用IO::Socket::INET模块,并编写了一个成功的测试端口的脚本,但如果可能的话,宁愿避免使用Perl。

注意:这是我的服务器正在运行(我需要从哪里运行这个)

SunOS 5.10 Generic_139556-08 i86pc i386 i86pc


当前回答

如果你想使用nc,但没有支持-z的版本,尝试使用——send-only:

nc --send-only <IP> <PORT> </dev/null

和timeout:

nc -w 1 --send-only <IP> <PORT> </dev/null

如果是IP,则不需要DNS查询:

nc -n -w 1 --send-only <IP> <PORT> </dev/null

它根据是否可以连接返回-z代码。

其他回答

在投票最多的答案的基础上,这里有一个等待两个端口打开的函数,还有一个超时。请注意必须打开的两个端口,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
}

如果您正在使用ksh或bash,它们都支持使用/dev/tcp/ ip / port构造将IO重定向到/从套接字。在这个Korn shell示例中,我将从套接字重定向no-op的(:)标准输入:

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中,所以如果stin重定向失败,我可以扔掉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从套接字读取。

正如B. Rhodes所指出的,nc (netcat)将完成这项工作。更紧凑的使用方法:

nc -z <host> <port>

这样,nc将只检查端口是否打开,成功时退出0,失败时退出1。

快速交互式检查(5秒超时):

nc -z -v -w5 <host> <port>

我的机器不支持nc或/dev/tcp/$hostname/$port,但支持超时,所以我回到telnet,如下所示:

if echo "quit" | timeout 2 telnet $SERVER $PORT 2>&1 | grep -q 'Connected to'; then
    echo "Connection to $SERVER on port $PORT succeeded"
    exit 0
else
    echo "Connection to $SERVER on port $PORT failed"
    exit 1
fi

在某些情况下,像curl, telnet, nc和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