Red Green Repeat Adventures of a Spec Driven Junkie

How to Find Process IDs on ports with `lsof`

tl;dr

To kill a process running on a specific port use lsof as so:

lsof -i :<process port number>

I want to tell you how to find the server process ID that is running a on a specific port. This is useful in a micro-service based development when you want to kill a server, not all of them.

I will apply this to a practical example of finding a server’s process ID and stopping the server.

You will understand a new Unix tool: lsof and understand how to incorporate it into your work-flow.

This article will take you about four minutes to read.

Damascus Room source and more information

Introduction

Ever have to stop a server process? It froze and you need to reset it, at no fault of your own?! :-)

Easy, use ps -aef to list all the process names and associated IDs. Put the output into grep to find the server name, and stop it using the command: kill -9 <pid value from ps -aef>

Here’s how to kill the jekyll web server:

vagrant@ubuntu-xenial:~/rgr$ ps -aef | grep jekyll
vagrant  29511  5837 29 09:16 pts/2    00:00:54 ruby /home/vagrant/.rvm/gems/ruby-2.4.6/bin/jekyll s

Enter Micro-services

What if you’re running a micro-service based application or multiple versions of the same application in parallel and needed to kill only one of them?

ps -aef would list process by their application name. If the process had the same options, this would be the result:

Example

vagrant  29511  5837 17 09:16 pts/2    00:01:15 ruby /home/vagrant/.rvm/gems/ruby-2.4.6/bin/jekyll s
vagrant  29568 29539 12 09:21 pts/3    00:00:13 ruby /home/vagrant/.rvm/gems/ruby-2.4.6/bin/jekyll s

Now, which process to stop? Stop them all and restart every other one? That might not be painful if the number of services is less than a handful.

As n Gets Large, so does Pain

It does get painful when there are two handfuls or more of services or applications.

With micro-services, there’s a good chance the only thing you can differentiate between the services are the port number each service is running on.

Is there a tool that can list which process is running on each port?

Yes, there is!

Enter: lsof

The tool is: lsof - short for: list open files. The specific option needed is the -i option, which lists open files that match an Internet address.

Seems like overkill, right?

These are the reasons for this:

  • Everything in UNIX is a file, running a micro-service requires running files.
  • Micro-services are listening to ports, connecting files to ports.

Using lsof, we are essentially asking: what files are open on which port?

Running lsof by itself:

vagrant@ubuntu-xenial:~/rgr$ lsof
COMMAND     PID  TID       USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
systemd       1            root  cwd   unknown                                        /proc/1/cwd (readlink: Permission denied)
systemd       1            root  rtd   unknown                                        /proc/1/root (readlink: Permission denied)
systemd       1            root  txt   unknown                                        /proc/1/exe (readlink: Permission denied)
systemd       1            root NOFD                                                  /proc/1/fd (opendir: Permission denied)
kthreadd      2            root  cwd   unknown                                        /proc/2/cwd (readlink: Permission denied)
kthreadd      2            root  rtd   unknown                                        /proc/2/root (readlink: Permission denied)
...
lsof      29509         vagrant  mem       REG                8,1  1668976      29183 /usr/lib/locale/locale-archive
lsof      29509         vagrant    4r     FIFO               0,10      0t0     149674 pipe
lsof      29509         vagrant    7w     FIFO               0,10      0t0     149675 pipe
ruby      29511          vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
ruby-time 29511 29512    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
thread_po 29511 29522    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
thread_po 29511 29523    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
serve.rb: 29511 29525    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)

To find out what process is on port 4000 (the jekyll server):

vagrant@ubuntu-xenial:~/rgr$ lsof | grep 4000
ruby      29511          vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
ruby-time 29511 29512    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
thread_po 29511 29522    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
thread_po 29511 29523    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)
serve.rb: 29511 29525    vagrant   14u     IPv4             148658      0t0        TCP *:4000 (LISTEN)

And to find out the PID of the jekyll server running on port 4001:

vagrant@ubuntu-xenial:~/rgr$ lsof | grep 4001
ruby      29568          vagrant   14u     IPv4             151277      0t0        TCP *:4001 (LISTEN)
ruby-time 29568 29569    vagrant   14u     IPv4             151277      0t0        TCP *:4001 (LISTEN)
thread_po 29568 29579    vagrant   14u     IPv4             151277      0t0        TCP *:4001 (LISTEN)
thread_po 29568 29580    vagrant   14u     IPv4             151277      0t0        TCP *:4001 (LISTEN)
serve.rb: 29568 29582    vagrant   14u     IPv4             151277      0t0        TCP *:4001 (LISTEN)

To stop the server, just pick the one I want to stop based on the port.

Can I do better?

lsof is the right tool, using it with grep does work. Is there a better way to use it?

Yes there is.

Looking at the lsof man page more, there’s an -i switch, specifically for IP addresses and ports.

-i [i] selects the listing of files any of whose Internet address matches the address specified in i. If no address is specified, this option selects the listing of all Internet and x.25 (HP-UX) network files.

Using lsof -i instead:

vagrant@ubuntu-xenial:~/rgr$ lsof -i :4000
COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ruby    29511 vagrant   14u  IPv4 148658      0t0  TCP *:4000 (LISTEN)

vagrant@ubuntu-xenial:~/rgr$ lsof -i :4001
COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ruby    29568 vagrant   14u  IPv4 151277      0t0  TCP *:4001 (LISTEN)

Produces the same result as lsof with grep. lsof -i produces a result faster as lsof by processes for every port, which can be over a 1000.

vagrant@ubuntu-xenial:~/rgr$ lsof | wc -l
1503

Conclusion

On Unix systems, Stopping servers can be as easy as using ps -aef and grep to figure out which process ID to kill.

When there are more than one server that runs with the same name, lsof -i will help you out more than ps -aef, if you know the port number.