繁体   English   中英

如何使用Python脚本启动和停止包含“ http.server.serveforever”的Python脚本

[英]How to use a Python script to start and stop a Python script containing “http.server.serveforever”

背景

我有一个名为server.py的Python 3脚本,它使用内置的http.server模块。 该脚本可归结为以下内容:

from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler

class MyRequestHandler (BaseHTTPRequestHandler):
    def do_POST(self):
        # Code omitted for brevity

    def do_GET(self):
        # Code omitted for brevity

def start_server():

    # Begin serving
    # -------------
    server = HTTPServer(('', port), MyRequestHandler)
    print("server now running on port {0} ...".format(port))

    server.serve_forever()

# Start the Server
# ----------------
if __name__ == '__main__':
    start_server()

MyRequestHandler通过“即时”导入模块来处理GET和POST请求,具体取决于用于请求的URI。

上面的方法工作正常,但是,在创建该脚本之后,需要能够远程更新脚本的整个“包”(即服务器脚本以及已加载的所有“模块脚本”即时”,位于子文件夹中)。

为此,我在Python 3中编写了另一个服务器脚本(称为updater.py ),该脚本将在得到指示时检索一个zip文件,然后将其解压缩以覆盖原始的server.py脚本以及所有其他相关的脚本和子脚本。 -文件夹。

这一切都很好,但是我现在碰壁了。 我认为,最好的方法是让updater.py脚本控制server.py的运行。 它可以关闭server.py以及与其链接的所有内容,然后再覆盖所有内容,然后在覆盖后重新启动它。

在此基础上,我走过的路是使用subprocess.Popen启动服务器,认为我可以在覆盖server.py之前杀死Python进程,但是,这并没有达到预期的效果。 这是我为测试该理论而编写的trial.py脚本:

import sys
import subprocess

def main():
    def start_process():
        proc = subprocess.Popen([sys.executable, 'server.py'])
        print("Started process:")
        print(proc.pid)
        return proc

    def kill_process(the_process):
        print("Killing process:")
        print(the_process.pid)
        the_process.kill()

    process = None

    while True:
        user_input = input("Type something: ")

        if user_input == 'start':
            process = start_process()
        if user_input == 'kill':
            kill_process(process)
        if user_input == 'exit':
            break

if __name__ == '__main__':
    main()

这似乎确实可以启动并杀死一个Python进程,但是此脚本在运行时服务器未在运行,因此我不确定它正在启动并终止什么! 键入“开始”然后“退出”(从而退出trial.py脚本)将允许服务器运行,尽管我不明白为什么,因为我认为subprocess.Popen应该导致生成的进程独立于父进程运行处理?

编辑:由于下面@HåkenLid的敏锐观察,我注意到我所做的一切只是打破了while循环, 而不是退出脚本。 这使我相信while循环以某种方式阻止了子进程的运行(因为一旦退出循环,服务器将启动)。

根据我们的讨论,我建议使用某种方法从“ server.py”中清空stdio缓冲区。 如果还希望能够提供用户输入,则在等待用户在主线程上输入时,需要一个线程来进行打印(或只是将缓冲区清空到黑洞中)。 这是我可能如何做的一个大概想法。

import sys
import subprocess
from threading import Thread 
#This could probably be solved with async, but I still
#haven't learned async as well as I know threads

def main():

    def start_process():
        proc = subprocess.Popen([sys.executable, 'server.py'], 
                                stdin=subprocess.PIPE, 
                                stdout=subprocess.PIPE)
        print("Started process:")

        def buf_readerd(proc, inbuf, outbuf):
            while proc.poll() is None:
                outbuf.write(inbuf.readline()) #may need to add a newline.. I'm not sure if readline ends in a \n

        stdoutd = Thread(target=buf_readerd, args=(proc, proc.stdout, sys.stdout), daemon=True)
        stderrd = Thread(target=buf_readerd, args=(proc, proc.stderr, sys.stderr), daemon=True)
        stdoutd.start()
        stderrd.start()
        print("started pipe reader daemons")

        print(proc.pid)
        return proc
# ...

好的,我想我已经自己修复此问题。 问题是我在while循环内通过调用input()阻止了子流程的执行。 在收到一些输入之前,脚本不执行任何操作。 我使subprocess.poll()成为循环的组成部分,并将对input()的调用置于该循环内。 如果几次击<return> ,服务器将启动并且可以使用它。 如果再键入kill ,则服务器将按预期终止。

我不确定在我的updater.py脚本的上下文中这将如何工作,但是我已经学到了一个有价值的课程,即“在发布到StackOverflow之前要更深入地思考”!

import sys
import subprocess

def main():
    def start_process():
        proc = subprocess.Popen([sys.executable, 'server.py'])
        print("Started process:")
        print(proc.pid)
        return proc

    def kill_process(the_process):
        print("Killing process:")
        print(the_process.pid)
        the_process.kill()

    user_input = input("Type something: ")

    if user_input == 'start':
        process = start_process()

        while process.poll() is None:
            user_input = input()
            if user_input == 'kill' or user_input == 'exit':
                kill_process(process)

if __name__ == '__main__':
    main()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM