测试远程 TCP 端口是否从 shell 脚本打开
我正在寻找一种快速而简单的方法,用于从 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
我要么需要更好的方法,或者是一种强制 telnet 在 8 秒内未连接的情况下超时的方法,并返回一些我可以在 Shell 中捕获的内容(返回代码或 stdout 中的字符串)。
我知道 Perl 方法,它使用 IO::Socket::INET 模块并编写了一个测试端口的成功脚本,但希望尽可能避免使用 Perl。
注意:这是我的服务器正在运行的(我需要从中运行它)
SunOS 5.10 Generic_139556-08 i86pc i386 i86pc
I'm looking for a quick and simple method for properly testing if a given TCP port is open on a remote server, from inside a Shell script.
I've managed to do it with the telnet command, and it works fine when the port is opened, but it doesn't seem to timeout when it's not and just hangs there...
Here's a sample:
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
I either need a better way, or a way to force telnet to timeout if it doesn't connect in under 8 seconds for example, and return something I can catch in Shell (return code, or string in stdout).
I know of the Perl method, which uses the IO::Socket::INET module and wrote a successful script that tests a port, but would rather like to avoid using Perl if possible.
Note: This is what my server is running (where I need to run this from)
SunOS 5.10 Generic_139556-08 i86pc i386 i86pc
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
正如 B. Rhodes 所指出的,
nc
(netcat
< /a>) 会完成这项工作。更紧凑的使用方式:这样
nc
将仅检查端口是否打开,成功时以 0 退出,失败时以 1 退出。对于快速交互式检查(5 秒超时):
As pointed by B. Rhodes,
nc
(netcat
) will do the job. A more compact way to use it:That way
nc
will only check if the port is open, exiting with 0 on success, 1 on failure.For a quick interactive check (with a 5 seconds timeout):
使用
nc
的-z
和-w TIMEOUT
选项很容易做到,但并非所有系统都有nc
> 已安装。如果您有足够新的 bash 版本,这将起作用:这里发生的情况是
timeout
将运行子命令,如果它没有在指定的超时内退出(上面的 1 秒),则将其终止例子)。在本例中,bash
是子命令,并使用其特殊的 /dev/tcp Handling 尝试打开与指定服务器和端口的连接。如果bash
可以在超时时间内打开连接,cat
将立即关闭它(因为它正在从/dev/null
读取)并退出状态代码0
将通过bash
传播,然后通过timeout
传播。如果bash
在指定的超时之前发生连接失败,则bash
将退出,退出代码为 1,timeout
也将返回。如果 bash 无法建立连接并且指定的超时到期,则timeout
将终止bash
并以状态 124 退出。对
使用不同的语法strong>Git Bash:
否则,Git Bash 将返回一个预期不会出现的错误:
It's easy enough to do with the
-z
and-w TIMEOUT
options tonc
, but not all systems havenc
installed. If you have a recent enough version of bash, this will work:What's happening here is that
timeout
will run the subcommand and kill it if it doesn't exit within the specified timeout (1 second in the above example). In this casebash
is the subcommand and uses its special /dev/tcp handling to try and open a connection to the server and port specified. Ifbash
can open the connection within the timeout,cat
will just close it immediately (since it's reading from/dev/null
) and exit with a status code of0
which will propagate throughbash
and thentimeout
. Ifbash
gets a connection failure prior to the specified timeout, thenbash
will exit with an exit code of 1 whichtimeout
will also return. And if bash isn't able to establish a connection and the specified timeout expires, thentimeout
will killbash
and exit with a status of 124.Use a different syntax for Git Bash:
Otherwise, Git Bash will return an error where none is expected:
目录:
nc
的使用 bash 和
timeout
:请注意,
timeout
应在 RHEL 6+ 中提供,或者在 GNU coreutils 8.22 中找到。在 MacOS 上,使用brew install coreutils
安装它,并将其用作gtimeout
。命令:
如果参数化主机和端口,请务必将它们指定为
${HOST}
和${PORT}
,如上所示。不要仅将它们指定为$HOST
和$PORT
,即不带大括号;在这种情况下它不起作用。示例:
成功:
失败:
如果必须保留
bash
的退出状态,请使用
nc
:请注意,将安装向后不兼容版本的
nc
在 RHEL 7 上。命令:
请注意,下面的命令是唯一的,因为它对于 RHEL 6 和 7 来说是相同的。只是安装和输出不同。
RHEL 6 (nc-1.84):
安装:
示例:
Success:
Failure:
如果主机名映射到多个 IP,则上述失败命令将循环遍历其中多个或全部 IP。例如:
RHEL 7 (nmap-ncat-6.40):
安装:
示例:
Success:
Failure:
如果主机名映射到多个 IP,则上述失败命令将循环遍历其中多个或全部 IP。例如:
备注:
-v
(--verbose
) 参数和echo $?
命令当然仅用于说明目的。TOC:
timeout
nc
Using bash and
timeout
:Note that
timeout
should be present with RHEL 6+, or is alternatively found in GNU coreutils 8.22. On MacOS, install it usingbrew install coreutils
and use it asgtimeout
.Command:
If parametrizing the host and port, be sure to specify them as
${HOST}
and${PORT}
as is above. Do not specify them merely as$HOST
and$PORT
, i.e. without the braces; it won't work in this case.Example:
Success:
Failure:
If you must preserve the exit status of
bash
,Using
nc
:Note that a backward incompatible version of
nc
gets installed on RHEL 7.Command:
Note that the command below is unique in that it is identical for both RHEL 6 and 7. It's just the installation and output that are different.
RHEL 6 (nc-1.84):
Installation:
Examples:
Success:
Failure:
If the hostname maps to multiple IPs, the above failing command will cycle through many or all of them. For example:
RHEL 7 (nmap-ncat-6.40):
Installation:
Examples:
Success:
Failure:
If the hostname maps to multiple IPs, the above failing command will cycle through many or all of them. For example:
Remarks:
The
-v
(--verbose
) argument and theecho $?
command are of course for illustration only.使用
netcat
可以检查端口是否打开,如下所示:如果TCP端口打开,
nc
的返回值将是成功,失败(通常返回码1) ) 如果无法建立 TCP 连接。当您尝试此操作时,某些版本的 nc 将会挂起,因为即使在从
/dev/null
接收到文件结尾后,它们也不会关闭套接字的发送部分。在我自己的 Ubuntu 笔记本电脑 (18.04) 上,我安装的netcat-openbsd
版本的 netcat 提供了一种解决方法:需要-N
选项才能立即得到结果:With
netcat
you can check whether a port is open like this:The return value of
nc
will be success if the TCP port was opened, and failure (typically the return code 1) if it could not make the TCP connection.Some versions of
nc
will hang when you try this, because they do not close the sending half of their socket even after receiving the end-of-file from/dev/null
. On my own Ubuntu laptop (18.04), thenetcat-openbsd
version of netcat that I have installed offers a workaround: the-N
option is necessary to get an immediate result:在 Bash 中,使用 伪设备文件 进行 TCP/UDP 连接非常简单。以下是脚本:
测试:
这是一行(Bash 语法):
请注意,某些服务器可以通过防火墙保护免受 SYN 洪水攻击,因此您可能会遇到 TCP 连接超时(约 75 秒)。要解决超时问题,请尝试:
请参阅:如何减少 TCP connect() 系统调用超时?
In Bash using pseudo-device files for TCP/UDP connections is straight forward. Here is the script:
Testing:
Here is one-liner (Bash syntax):
Note that some servers can be firewall protected from SYN flood attacks, so you may experience a TCP connection timeout (~75secs). To workaround the timeout issue, try:
See: How to decrease TCP connect() system call timeout?
我需要一个更灵活的解决方案来处理多个 git 存储库,因此我根据 1 和 2。您可以使用您的服务器地址代替 gitlab.com,并使用您的端口代替 22。
I needed a more flexible solution for working on multiple git repositories so I wrote the following sh code based on 1 and 2. You can use your server address instead of gitlab.com and your port in replace of 22.
使用 bash 检查端口
示例
端口 22 已打开
代码
check ports using bash
Example
the port 22 is open
Code
如果您使用 ksh 或 bash,它们都支持使用 /dev/tcp/IP/PORT 结构将 IO 重定向到套接字或从套接字重定向。在这个 Korn shell 示例中,我从套接字重定向无操作 (:) std-in:
如果套接字未打开,shell 会打印错误:
因此您可以在 if 条件下使用它作为 测试:
无操作位于子 shell 中,因此如果 std-in 重定向失败,我可以丢弃 std-err。
我经常使用/dev/tcp来检查HTTP上资源的可用性:
这一行打开文件描述符9来读取和写入套接字,打印HTTP GET 到套接字并使用
cat
从套接字读取。If you're using ksh or bash they both support IO redirection to/from a socket using the /dev/tcp/IP/PORT construct. In this Korn shell example I am redirecting no-op's (:) std-in from a socket:
The shell prints an error if the socket is not open:
You can therefore use this as the test in an if condition:
The no-op is in a subshell so I can throw std-err away if the std-in redirection fails.
I often use /dev/tcp for checking the availability of a resource over HTTP:
This one-liner opens file descriptor 9 for reading from and writing to the socket, prints the HTTP GET to the socket and uses
cat
to read from the socket.虽然是一个老问题,但我刚刚处理了它的一个变体,但这里的解决方案都不适用,所以我找到了另一个问题,并为后代添加它。是的,我知道OP说他们知道这个选项,但它不适合他们,但对于后来的任何人来说,它可能会被证明是有用的。
就我而言,我想测试来自
docker
构建的本地apt-cacher-ng
服务的可用性。这意味着在测试之前绝对不能安装任何东西。没有 nc、nmap、expect、telnet 或 python。然而,perl 以及核心库都存在,所以我使用了这个:While an old question, I've just dealt with a variant of it, but none of the solutions here were applicable, so I found another, and am adding it for posterity. Yes, I know the OP said they were aware of this option and it didn't suit them, but for anyone following afterwards it might prove useful.
In my case, I want to test for the availability of a local
apt-cacher-ng
service from adocker
build. That means absolutely nothing can be installed prior to the test. Nonc
,nmap
,expect
,telnet
orpython
.perl
however is present, along with the core libraries, so I used this:在某些情况下,像curl、telnet、nc on nmap这样的工具不可用,您仍然有机会使用wget
In some cases where tools like curl, telnet, nc o nmap are unavailable you still have a chance with wget
如果您想使用
nc
但没有支持-z
的版本,请尝试使用--send-only
:并设置超时:
如果是 IP,则无需进行 DNS 查找:
它会根据是否可以连接以
-z
形式返回代码。If you want to use
nc
but don't have a version that support-z
, try using--send-only
:and with timeout:
and without DNS lookup if it's an IP:
It returns the codes as the
-z
based on if it can connect or not.基于投票最高的答案,这里有一个等待两个端口打开的函数,并且还有一个超时。请注意必须打开的两个端口:8890 和 1111,以及 max_attempts(每秒 1 次)。
Building on the most highly voted answer, here is a function to wait for two ports to be open, with a timeout as well. Note the two ports that mus be open, 8890 and 1111, as well as the max_attempts (1 per second).
我需要在 cron 中运行但没有输出的简短脚本。我使用 nmap 解决了我的问题
要运行它,您应该安装 nmap,因为它不是默认安装的软件包。
I needed short script which was run in cron and hasn't output. I solve my trouble using nmap
To run it You should install nmap because it is not default installed package.
我猜想现在回答已经太晚了,这可能不是一个好的答案,但是你可以...
将它放在一个带有某种计时器的 while 循环中怎么样?与 Solaris 相比,我更喜欢 Perl,但根据您使用的 shell,您应该能够执行以下操作:
然后在 while 循环中添加一个标志,这样如果在完成之前超时,您可以引用超时作为失败的原因。
我怀疑 telnet 也有一个超时开关,但就在我的脑海中,我认为上面的方法会起作用。
I'm guessing that it's too late for an answer, and this might not be a good one, but here you go...
What about putting it inside of a while loop with a timer on it of some sort. I'm more of a Perl guy than Solaris, but depending on the shell you're using, you should be able to do something like:
And then just add a flag in the while loop, so that if it times out before completing, you can cite the timeout as reason for failure.
I suspect that the telnet has a timeout switch as well, but just off the top of my head, I think the above will work.
这在幕后使用 telnet,并且似乎在 mac/linux 上工作得很好。由于 linux/mac 上的版本之间存在差异,它不使用 netcat,并且这适用于默认的 mac 安装。
示例:
is_port_open.sh
This uses telnet behind the scenes, and seems to work fine on mac/linux. It doesn't use netcat because of the differences between the versions on linux/mac, and this works with a default mac install.
Example:
is_port_open.sh
我的机器不支持
nc
或/dev/tcp/$hostname/$port
但timeout
,所以我回到telnet如下:
My machine does not support
nc
or/dev/tcp/$hostname/$port
buttimeout
, so I came back totelnet
as follows:nmap-ncat 用于测试尚未使用的本地端口
nmap-ncat to test for local port that is not already in use