2

In a linux shell, I can run this command to kill every process created by my python script (started by sudo python3 server.py):

sudo kill -9 `ps -ef | grep server.py |grep -v "grep"|awk '{{print $2}}'

I wanted to add this to my script and end any previous script process at start, to a avoid getting a socket "Address already in use" error.

Here's my code:

    try:
        application.listen(port=63)
    except OSError as e:
        if e.errno == errno.EADDRINUSE:
            cmd = 'sudo kill -9 `ps -ef | grep server.py |grep -v "grep"|awk \'{{print $2}}\'`'
            print('try to kill previous',cmd)
            import os
            os.system(cmd)

The problem is that this also kill the new process, because it's also started by the same keyword.

How can I avoid this?

KurzedMetal
  • 12,540
  • 6
  • 39
  • 65
user2003548
  • 4,287
  • 5
  • 24
  • 32
  • 2
    First of all: that is a bad idea. What if you kill something important by accident? Secondly: you are checking for `EADDRINUSE`. Your code may throw it even though there is no `server.py` running in the background, because OS didn't have enough time to reset the socket. Generally you are doing it wrong! – freakish Aug 27 '13 at 14:22
  • i want to know how to do it. i didn't decide it's danger or not.or safer way to accomplish this mission? – user2003548 Aug 27 '13 at 14:24
  • 1
    I like to avoid using commandline in python, most times there's a useful module around, like [`psutil`](http://code.google.com/p/psutil/) in this case, unfortunately I have barely any experience with it, but you can access processes and networking information (maybe get the pid of the program binding at that port) – KurzedMetal Aug 27 '13 at 14:27
  • 1
    @user2003548 Safer way is to add a server shutdown method to your app (triggered for example via TCP). Then you write a separate script which will handle server shutdown. And at the end your main script has to do `app.listen(...)` in a loop (in case of `TIME_WAIT` on a socket). – freakish Aug 27 '13 at 14:29
  • See also http://stackoverflow.com/a/18159055/841108 – Basile Starynkevitch Aug 27 '13 at 14:42
  • Your server process should not know that your system has another one process of your script. Ubuntu upstart init system has build-in function for checking process status. In any other system you can add cronjob which will be checking process status and restart your server. And use locks for running only one instance at time. – Alexander Gryanko Aug 27 '13 at 14:48
  • 3
    `kill -9` should be a last resort, not a standard approach. The default signal sent by `kill` should be sufficient. – chepner Aug 27 '13 at 15:24
  • i did apply a shutdown method in the application,but sometimes the server trapped into some loop state and won't receive the command from outside. – user2003548 Aug 28 '13 at 16:21

2 Answers2

2

Instead of killing the program by name you could simply kill the program that is listening on port 63.

The following command gives you the PID of the program listening on port 63

netstat --numeric-ports --listening --program | awk '{if (match($4, ":63$")) { split($NF, a, "/"); print a[1];}}' 

Or in a shorter form:

netstat -nlp | awk '{if (match($4, ":63$")) {split($NF, a, "/"); print a[1];}}' 

Gluing everything together the command to kill the program listening on port 63 is the following:

sudo kill -9 `netstat -nlp | awk '{if (match($4, ":63$")) {split($NF, a, "/"); print a[1];}}'`

Here the explanation:

netstat -nlp outputs all the programs listening on some ports without resolving the port names.

Thus one gets something like this:

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      2096/php-fpm.conf)
tcp        0      0 127.0.0.1:63            0.0.0.0:*               LISTEN      2263/memcached  
tcp        0      0 0.0.0.0:36815           0.0.0.0:*               LISTEN      1748/rpc.statd 
....

The awk command has the following meaning:

  awk '{
       # check if field "Local Address" ends with ":63"
       if (match($4, ":63$")) {

           # split the field "PID/Program name" 
           # into the array a based on delimiter "/"
           split($NF, a, "/");

           # print the PID  
           print a[1];

       }
  }'
wooghie
  • 437
  • 2
  • 8
  • it didn't work when there's multi process,if the child process haven't been killed, the address won't be released. – user2003548 Aug 28 '13 at 16:17
  • Have you already tried to kill all the children? Here some hints to do so: http://stackoverflow.com/questions/392022/best-way-to-kill-all-child-processes/6481337#6481337 – wooghie Aug 28 '13 at 19:11
1

You can use the psutil module to get process and networking information

import psutil
import pprint

for process in psutil.process_iter():
    ### find which ports is the listening (if any)
    listening_ports = [conn for conn in process.get_connections() if conn.status == psutil.CONN_LISTEN]
    if len(listening_ports) > 0:
        print("PID: {}, Process Name: {}".format(process.pid, process.name))
        print("Connections:")
        pprint.pprint(listening_ports)
    ### You could check the desired process and terminate/kill it
    # process.terminate()

Example Output on Windows, the module supports Linux too (list all listening processes):

PID: 664, Process Name: lsass.exe
Connections:
[connection(fd=-1, family=2, type=1, laddr=('0.0.0.0', 49155), raddr=(), status='LISTEN'),
 connection(fd=-1, family=23, type=1, laddr=('::', 49155), raddr=(), status='LISTEN')]
PID: 904, Process Name: svchost.exe
Connections:
[connection(fd=-1, family=2, type=1, laddr=('0.0.0.0', 135), raddr=(), status='LISTEN'),
 connection(fd=-1, family=23, type=1, laddr=('::', 135), raddr=(), status='LISTEN')]
PID: 1712, Process Name: SpiderOak.exe
Connections:
[connection(fd=-1, family=2, type=1, laddr=('127.0.0.1', 49201), raddr=(), status='LISTEN'),
 connection(fd=-1, family=2, type=1, laddr=('0.0.0.0', 49258), raddr=(), status='LISTEN')]

With all this information you can find your process and even kill it with the psutil.Process methods terminate() (sends SIGTERM signal) or kill() (sends SIGKILL signal, just like kill -9)

KurzedMetal
  • 12,540
  • 6
  • 39
  • 65