Python启动一个完全独立于启动过程的进程

2024-09-29 17:13:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是python2.5.2或2.7,这是一个HTTP服务器(BaseHTTPServer),可以启动各种任务。其中一个进程是长时间运行的进程。我希望能够做的是启动这个进程,然后关闭我的HTTP服务器并重新启动。在

问题是我的服务器关闭(关闭所有线程和python.exe进程退出Windows显示的活动任务列表,启动的进程仍在运行,但是netstat-ab显示系统进程有我的端口,HTTP服务器在监听状态下监听,并且与进程ID相关联,这个进程ID曾经是我的HTTP服务器。在启动的进程完成之前,该端口一直保持打开状态,这使得无法重新启动我的HTTP服务器。在

无论我终止python进程,还是CTRL-C窗口,都会显示相同的行为。我读了大量的文档,每个人都建议使用子流程.Popen,但即使使用它,似乎也会将主进程的一部分与已启动的进程相关联。在

我将按如下方式启动该实用程序:

try:

    # NOTE: subprocess.Popen is hanging up the 8091 port until the utility finishes.
    #       This needs to be addressed, otherwise, I'll never be able to restart the
    #       client when the utility has been launched.

    listParams = [ 'C:/MyPath/My.exe', '-f', os.path.join ( sXMLDir, sXmlFile ) ]

    proc = subprocess.Popen ( listParams, cwd='C:/MyPath', creationflags=0x00000008 )
    iSts = 200
    sStatus = 'Utility was successfully launched.'

except:
    iSts = CMClasses.HTTPSTS_STARTSLEDGE_SYSTEM
    sStatus = 'An exception occurred launching utility: ' + str ( sys.exc_type ) + ":" + str ( sys.exc_value  ) + '.'

我的HTTP服务器实现如下,它允许我的主程序处理CTRL-C:

^{pr2}$

下面是netstat-ab(我的python进程是3728,端口是8091)在启动实用程序之前的结果:

活动连接

协议本地地址外部地址状态PID

TCP vtxshm-po-0101:8091 vtxshm-po-0101:0监听3728 [python.exe]在

TCP vtxshm-po-0101:8091 vtxshm-po-0101:23193时间_WAIT 0 [框架服务.exe]在

下面是netstat-ab在启动实用程序后,在点击Control-C并停止python之后的结果。(请注意,操作系统认为该端口仍处于侦听状态,分配给PID 3728,但该进程已不存在于任务管理器中,它现在由系统拥有,并以某种方式与snmp.exe(我们甚至不用)。这些连接被理解为来自另一个服务器以启动实用程序的请求。在

活动连接

协议本地地址外部地址状态PID

TCP vtxshm-po-0101:8091 vtxshm-po-0101:0监听3728 [系统]

TCP vtxshm-po-0101:8091 CH2ChaosMon公司密钥服务器:2133 TIME_WAIT0 TCP vtxshm-po-0101:8091 CH2ChaosMon公司密钥服务器:2134 TIME_WAIT0 TCP vtxshm-po-0101:8091 vtxshm-po-0101:23223时间_WAIT 0 [snmp.exe]在

是否有人成功地从python启动了一个进程,并且完全独立于启动过程运行?如果是的话,你能告诉我这个秘密吗?在


Tags: the端口实用程序服务器httpab进程状态
2条回答

所以你可以定义:

def run ( self ):
    server = stoppableHttpServer(('',self.Port), self.CMRequestHandler )
    server.serve_forever()
    server.socket.close()

在这里,实例中不保留对变量server的引用。这是一个问题,因为它意味着不可能更改下面类中的self.stop标志:

^{pr2}$

当您执行server_forever方法时,它会阻塞它的线程。由于没有保留对其父实例的引用,因此无法设置self.stop = True。实际上,在代码中没有尝试这样做,所以套接字很可能挂起。如果handle_request正在阻塞(如果不设置超时,这也是一个问题)。在

您应该注意到serve_forever的默认实现可以用server.shutdown停止,因此检查self.stop标志的状态是多余的。在

我建议将您的LaunchHTTPServer类更新为如下内容:

# as the only part of the code that needs to run as a thread is the serve_forever method
# there is no need to have this class as a thread
class LaunchHTTPServer (object):
    def __init__ ( self, sPort, CMRequestHandler ):
        self.notifyWindow     = None
        self.Port             = sPort
        self.CMRequestHandler = CMRequestHandler
        self.bExecute         = True
        self.server           = None
        self.server_thread    = None 

    def start ( self ):
        # Here you can use the default HTTPServer implementation, as the server is already stoppable
        self.server = BaseHTTPServer.HTTPServer(('',self.Port), self.CMRequestHandler )
        self.server_thread = Thread(target=self.server.serve_forever)
        self.server_thread.start()

    def stop( self ):
        try:
            self.server.shutdown()
            self.server.socket.close()
            self.server_thread.join()
            self.server,self.server_thread = None,None
         except Exception as error:
            pass # catch and raise which ever errors you desire here 


    def getExecute ( self ):
        return ( self.bExecute )

    def endThread ( self ):
        pass

通过上面的设置,您现在可以从键盘捕捉Ctrl-C中断,并确保调用实例的stop方法来干净地关闭套接字并退出。在

我要回答一个稍微不同的问题,因为这是我能找到的最接近的类似问题。在

我遇到了一个程序的问题,该程序监听端口并使用子流程.Popen(). 如果我正在执行的脚本在后台运行一个长时间运行的作业(通过),并且我终止了主程序,则长时间运行的作业将接管主程序的侦听端口。在

主程序:

import BaseHTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler
import subprocess

class RequestHandler(BaseHTTPRequestHandler):
   def do_GET(self):
        proc = subprocess.Popen('start_long_proc.sh', shell=True)
        stdout, stderr = proc.communicate(input)

        self.send_response(200)
        self.end_headers()
        self.wfile.write('request served')

httpd = BaseHTTPServer.HTTPServer(('', 8000), RequestHandler)
httpd.serve_forever()

当httpd服务器接收到一个请求时,它将运行“start”long_工艺sh'. 脚本如下所示:

^{pr2}$

开始\u long_工艺sh立即返回,请求服务完成。现在问题来了:

如果我在sleep仍在运行时终止web服务器,sleep将接管侦听端口:

$ netstat -pant | grep 0.0.0.0:8000
tcp    0   0 0.0.0.0:8000    0.0.0.0:*   LISTEN      24809/sleep     

解决方案是在调用脚本时关闭除0、1和2(stdin、stdout、stderr)以外的所有文件描述符。Popen()为此提供了一个标志“close_fds”:

proc = subprocess.Popen('start_long_proc.sh', shell=True, close_fds=True)

现在睡眠不再束缚监听端口:

$netstat-pant | grep 0.0.0.0:8000 美元

发生这种情况的原因是子进程从其父进程继承打开文件描述符。让我恼火的是它包括监听端口。我以前见过“close”选项,但认为它也关闭了STDIN、STDOUT和STDERR。但它没有,所以您仍然可以像正常一样与子进程通信。在

相关问题 更多 >

    热门问题