Wait until TCP port opened using bash and nc
Recently, I wrote a shell script which interacts with a TCP server. Since the script took charge of launching the server, sometimes my script fails because the server did not open the socket yet.
To come up with this problem, I used to wait certain amount of time
using sleep(1)
like this:
# launch the server which automatically daemonizes itself.
start-server
# one second is enough for my system.
sleep 1
client do something
It was fine for my system, until I realized this method would not work on slow machine. Worse, when my system in a heavy-load, my system also failed to run above script successfully.
I would solve this problem by raising the amount of seconds sleeping, but I do not want to wait more on my relatively fast system.
Then I realized that netcat (a.k.a. nc
) provides such feature with
the "-z" option.
To test whether www.cinsk.org
(TCP port 80) is opened, I can launch
# In BSD-like (MacOS) system
$ nc -z www.cinsk.org 80
Connection to www.cinsk.org 80 port [tcp/http] succeeded!
$ _
# On my Linux system, no message but just return zero on success
$ nc -z www.cinsk.org 80
$ _
Then I found another problem. Suppose that the firewall drops all
packets for that port. Since by default, netcat(nc
) will wait
permanently until the port is open, the script that uses netcat(nc
)
will not return.
Thanks to the rich interface of netcat, it provides another option
"-w" to specify the amount of time it will wait. The problem is,
MacOS nc (BSD) does not work with "-w" option if the firewall drops
all packets. Installing GNU version will solve this problem. (by the
command "brew install netcat
")
Finally, I wrote wait4tcp.sh to lessen the burden for others.
# Wait until port 80 8080 5984 are opened
$ ./wait4tcp.sh HOSTNAME 80 8080 5984
# The same as above, except it will retry only 10 times per each port.
$ ./wait4tcp.sh -w 10 HOSTNAME 80 8080 5984
# Wait until port 80 is closed
$ ./wait4tcp.sh -c HOSTNAME 80
# The same as above, except it will retry permanently.
$ ./wait4tcp.sh -w -1 -c HOSTNAME 80
# With the bash brace expansion, wait for port range 6379..6383 are opened
$ ./wait4tcp.sh HOSTNAME {6379..6383}
By default, wait4tcp.sh will retry 100 times per each port. Retrying 100 times is done less than 1 second in my system. Using "-w -1" option will retry permanently.
Updated
Recently, I read valuable article from TCP Port Scanner in Bash, and found that bash provides special filenames for redirections.
As Peteris suggested, I changed to bash special filenames and
timeout(1)
so that there is no dependency to netcat(nc
).
Here is the full source code for wait4tcp.sh
:
<script src="https://gist.github.com/3769111.js"> </script>
Comments
Comments powered by Disqus