【问题标题】:kill process through shell without kill itself通过shell杀死进程而不杀死自己
【发布时间】:2013-08-27 14:19:33
【问题描述】:

在 linux shell 中,我可以运行这个命令来杀死我的 python 脚本(由sudo python3 server.py 启动)创建的每个进程:

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

我想将此添加到我的脚本并在开始时结束任何以前的脚本进程,以避免出现套接字“地址已在使用”错误。

这是我的代码:

    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)

问题是这也会杀死新进程,因为它也是由相同的关键字启动的。

我怎样才能避免这种情况?

【问题讨论】:

  • 首先:这是个坏主意。如果你不小心杀死了重要的东西怎么办?其次:您正在检查EADDRINUSE。即使后台没有运行server.py,您的代码也可能会抛出它,因为操作系统没有足够的时间来重置套接字。通常你做错了!
  • 我想知道怎么做。我没有决定这是否危险。或者更安全的方式来完成这项任务?
  • 我喜欢避免在 python 中使用命令行,大多数情况下都有一个有用的模块,比如 psutil 在这种情况下,不幸的是我几乎没有任何经验,但你可以访问进程和网络信息(也许在该端口获取程序绑定的 pid)
  • @user2003548 更安全的方法是向您的应用程序添加服务器关闭方法(例如通过 TCP 触发)。然后你编写一个单独的脚本来处理服务器关闭。最后,您的主脚本必须循环执行app.listen(...)(如果TIME_WAIT 在套接字上)。
  • kill -9 应该是最后的手段,而不是标准方法。 kill发送的默认信号应该足够了。

标签: python linux shell


【解决方案1】:

您可以简单地杀死程序,而不是按名称杀死程序 杀死正在侦听端口 63 的程序。

以下命令为您提供侦听端口 63 的程序的 PID

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

或者更短的形式:

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

将所有内容粘合在一起,终止侦听端口 63 的程序的命令如下:

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

解释如下:

netstat -nlp 输出所有侦听某些端口的程序,而不解析端口名称。

因此得到这样的结果:

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

awk 命令含义如下:

  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];

       }
  }'

【讨论】:

  • 多进程时不起作用,如果子进程没有被杀死,地址不会被释放。
  • 你是否已经试图杀死所有的孩子?这里有一些提示:stackoverflow.com/questions/392022/…
【解决方案2】:

您可以使用psutil 模块获取进程和网络信息

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()

Windows 上的示例输出,该模块也支持 Linux(列出所有监听进程):

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')]

有了所有这些信息,您可以找到您的进程,甚至可以使用psutil.Process 方法terminate()(发送SIGTERM 信号)或kill()(发送SIGKILL 信号,就像kill -9)杀死它

【讨论】:

  • 这将是一个备份解决方案,缺点是必须使用额外的插件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-08
  • 2011-06-05
  • 2018-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多