46

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

...
Will
  • 603

5 Answers5

73

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.

  • I think netcat is the answer, so thank you. To clarify, what I'm trying to do is write a script as part of a load balancing procedure. I need to start a process, wait for it to accept requests on the port and then shutdown the original. If there are better ways of doing this, rather than writing my own script, I'm all ears. – Will Dec 31 '10 at 16:36
  • @Will: That's a very different question! I've written a different answer. – Gilles 'SO- stop being evil' Dec 31 '10 at 17:37
  • 1
    I like netcat solution too. I have a script using nc -w 2 </dev/null >/dev/null — if the connection takes more than 2 seconds, it times out and fails — which is handy for my usage. – ephemient Jan 09 '11 at 23:10
  • FYI, I can't get the 'while nc -q 1 localhost 13000 </dev/null; do sleep 10; done' one to work. It just returns immediately. The first one works fine though. Thanks! – Ellis Percival Mar 19 '15 at 16:04
  • @Flyte nc -q 1 localhost 13000 </dev/null returns immediately if no server is listening, but it returns with an error code, so the loop makes it sleep and try again a few seconds later. – Gilles 'SO- stop being evil' Mar 19 '15 at 17:16
  • @Gilles It's for this reason that we need a ! in there to negate its output. I've submitted an edit to fix it :) – Ellis Percival Mar 19 '15 at 21:00
  • Is there a reason you use ! nc -q 1 localhost 13000 </dev/null instead of ! nc -z localhost 13000 &> /dev/null? -z seems to do exactly what you want - check if a port is listening. – dimo414 Dec 10 '17 at 03:47
  • @dimo414 Portability: traditional nc doesn't have -z. – Gilles 'SO- stop being evil' Dec 10 '17 at 05:30
  • OSX's nc doesn't have -q, but it does have -z :) – dimo414 Dec 10 '17 at 08:06
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

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
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.

tomups
  • 101