45

I need a command that will wait for a process to start accepting requests on a specific port.

Is there something in linux that does that?

while (checkAlive -host localhost -port 13000 == false)
  do some waiting

...
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Will
  • 593
  • 1
  • 4
  • 6

5 Answers5

72

The best test to see if a server is accepting connections is to actually try connecting. Use a regular client for whatever protocol your server speaks and try a no-op command.

If you want a lightweight TCP or UDP client you can drive simply from the shell, use netcat. How to program a conversation depends on the protocol; many protocols have the server close the connection on a certain input, and netcat will then exit.

while ! echo exit | nc localhost 13000; do sleep 10; done

You can also tell netcat to exit after establishing the connection. It returns 1 if there's no connection and 0 if there is so we negate its output. Depending on your version of netcat, it may support one or both of the following commands:

while ! nc -z localhost 13000 </dev/null; do sleep 10; done
while ! nc -q 1 localhost 13000 </dev/null; do sleep 10; done

An alternative approach is to wait for the server process to open a listening socket.

while netstat -lnt | awk '$4 ~ /:13000$/ {exit 1}'; do sleep 10; done

If you are on Mac OS, netstat uses a slightly different output format, so you would want the following intead:

while netstat -lnt | awk '$4 ~ /\.13000$/ {exit 1}'; do sleep 10; done

Or you might want to target a specific process ID:

while ! lsof -n -Fn -p $pid | grep -q '^n.*:13000$'; do sleep 10; done

I can't think of any way to react to the process starting to listen to the socket (which would avoid a polling approach) short of using ptrace.

Dwight Guth
  • 103
  • 2
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
21

If you have bash and coreutils (e.g. timeout, sleep), but not nc/lsof/netstat, you can use this solution which uses bash magic tcp sockets:

while ! timeout 1 bash -c "echo > /dev/tcp/localhost/13000"; do sleep 10; done
kanaka
  • 311
  • 2
  • 4
  • To elaborate, Bash has the optional feature of connecting to TCP sockets using "network redirections" -- https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Redirections – johntellsall Dec 23 '14 at 17:25
  • I wonder under which conditions it'll block... – x-yuri Jan 12 '21 at 21:51
18

Following the previous example with bash tcp sockets magic, here is an enhanced version which waits for connection during limited amount of time.

timeout 15 bash -c 'until echo > /dev/tcp/localhost/13000; do sleep 0.5; done'

The difference is that if connection wasn't available during 15s, - it won't loop forever but exit with the error code.

This is useful in init scripts to wait for service readiness/availability after startup.

Eugen
  • 281
  • 2
  • 4
2

I have written a utility to wait for a port to open, it can also check MySQL, PostgreSQL, Redis and etc availability.

# Checking TCP port
wait4x tcp localhost:8080

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

It's open source and available at https://github.com/atkrad/wait4x. Hopefully others will find it useful!

atkrad
  • 21
  • 1
0

I used this to wait for a couple of ports to be open, without netcat:

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

Change localhost and the ports as needed.

tomtastico
  • 101
  • 1