如何使用netcat等待开放端口?

94

我想用自定义的dockerfile在jenkins中运行。我希望等待端口8080打开,而不是用netcat进行“sleep 60”等待。但是我对bash脚本和netcat并不很熟悉。

这是我尝试做的一个示例:

#!/bin/bash
 
opened=0
 
while [ "$opened"  == "0" ]; do
  echo "Waiting jenkins to launch on 8080..."
  nc -vz localhost 8080
done
 
echo "Jenkins launched"
14个回答

158

你无法设置netcat等待某个端口打开,因此必须添加等待部分,然后再进行下一次检查。尝试这样做:

#!/bin/bash

echo "Waiting jenkins to launch on 8080..."

while ! nc -z localhost 8080; do   
  sleep 0.1 # wait for 1/10 of the second before check again
done

echo "Jenkins launched"

16
最终我使用了一个curl脚本来完成它:while ! curl --output /dev/null --silent --head --fail http://localhost:8080; do sleep 1 && echo -n .; done; - FXG
1
作为建议,您还可以在netcat命令中减少连接超时时间,以便在Jenkins启动时获得更快的响应。即 nc -G 1 -z localhost 8000 - Rarylson Freitas
2
nc:无效选项--'z' - odiszapc
1
如果你使用 man 命令,你会发现 -z 选项并不是无效的选项:" -z 选项指定 nc 只扫描监听守护进程,而不向它们发送任何数据。在与 -l 选项一起使用时,使用此选项是错误的。" - user987339
这很棒!在Alpine Linux中作为一行代码非常有效:while ! nc -z localhost 8080; do sleep 0.1; done - PhilT
显示剩余3条评论

76

我建议以下的一句话:

## netcat version:
timeout 22 sh -c 'until nc -z $0 $1; do sleep 1; done' stackoverflow.com 443

## pure bash version:
timeout 22 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' stackoverflow.com 443

两个命令在连接建立后立即退出,在最多22秒内每秒尝试一次。

请注意,由于timeout命令的存在,当端口可访问时,退出代码为0,否则为124(如果在给定时间内没有建立连接)。


8
纯bash版本很棒!可以在许多场景下使用。谢谢! - hao
1
">>" 更安全,因为它不会创建新文件或覆盖现有文件。 - Onlyjob

18

这里所建议的那样,如果您没有安装nc,但只有bashcoreutils,您也可以执行以下操作:

#!/bin/bash

echo "Waiting jenkins to launch on 8080..."

while ! timeout 1 bash -c "echo > /dev/tcp/localhost/8080"; do   
  sleep 1
done

echo "Jenkins launched"

我想知道,echo > ... 会阻塞吗?在什么情况下会阻塞? - x-yuri

12

我发现这是一个很常见的问题,因此编写了一个工具来等待端口打开,可选择超时:

# without timeout
wait-port localhost:8080

# timeout after a minute
wait-port -t 60000 localhost:8080

它是开源的,可以在github.com/dwmkerr/wait-port上获取。希望其他人会发现它有用!


11

为了进一步说明用户987339的答案,以下是如何在终端中轻松等待端口:

waitport函数

将此函数添加到您的~/.bashrc设置文件中:

waitport() {
    while ! nc -z localhost $1 ; do sleep 1 ; done
}

退出并重新登录以加载~/.bashrc。然后,运行此命令以验证端口3000是否有服务器在监听:

$ waitport 3000
Connection to localhost port 3000 [tcp/hbci] succeeded!

此已在 macOS 上验证。可能无法在 Fedora/CentOS 上工作,因为它们缺少 netcat-z 选项。


5

我用这个方法等待一些端口打开,而不需要使用netcat:

while (! (: </dev/tcp/localhost/27017) &> /dev/null || ! (: </dev/tcp/localhost/9200) &> /dev/null); do
    sleep 2;
done

localhost和端口更改为所需的值。


4

这是一个使用netcat的一行Bash解决方案,等待10秒钟以获取TCP连接,并在等待期间向您反馈是否成功,如果端口打开则返回退出码0,否则返回1

bash -c 'echo -n "Waiting port 8080 .."; for _ in `seq 1 40`; do echo -n .; sleep 0.25; nc -z localhost 8080 && echo " Open." && exit ; done; echo " Timeout!" >&2; exit 1'

如果代码片段被保存在脚本文件wait-port中,并在控制台中使用wait-port 8080调用,则可以通过$1替换硬编码的端口8080并删除bash -c

这是三个终端的录制,其中两个等待端口打开,另一个终端打开其中一个端口,因此当等待成功时,另一个超时:

wait-port test

尽管该行有很多指令,但如果需要在无法先将脚本存储在主机上的情况下“远程”执行等待,例如在Docker容器中,它可能会很有用。


3

在CI运行测试之前,我使用这个脚本来检查端口。

#!/bin/bash

for _ in `seq 1 20`; do
    echo -n .
    if nc -z localhost $1; then
        exit 0
    fi
    sleep 0.5
done

exit 1

$ bin/wait-port 3306

3

我编写了一个工具来等待端口打开,它还可以检查MySQL、PostgreSQL、Redis等的可用性。

# Checking TCP port
wait4x tcp localhost:8080

# Checking TCP port with specific timeout (5 Minutes)
wait4x tcp localhost:8080 -t 5m

这是一个开源项目,可以在https://github.com/atkrad/wait4x上找到。希望其他人也会觉得它有用!


3

下面是一段带有超时的for循环示例,它尝试执行10次,采用指数退避(2、4、8、16秒等),最终放弃。Netcat也有1秒超时时间。

for EXPONENTIAL_BACKOFF in {1..10}; do
    nc -w 1 -z db.local 3306 && break;
    DELAY=$((2**$EXPONENTIAL_BACKOFF))
    echo "db not yet available, sleeping for $DELAY seconds"
    sleep $DELAY
done

输出结果为:

db not yet available, sleeping for 2 seconds
db not yet available, sleeping for 4 seconds
db not yet available, sleeping for 8 seconds
db not yet available, sleeping for 16 seconds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接