Как убить SimpleHTTPServer из скрипта Python?

Я пытаюсь использовать http.server для проверки всех ссылок в проекте Python. Я могу заставить свой скрипт работать, если я запущу сервер перед запуском своего скрипта, а затем сервер остановится, когда я закрою окно терминала. Но мне бы очень хотелось, чтобы скрипт сам запускал и останавливал сервер.

Я сделал тестовый сценарий, чтобы просто запустить сервер, получить страницу и убедиться, что сервер работает, а затем остановить сервер. Я не могу получить pid сервера. Когда я пытаюсь убить pid, о котором этот скрипт сообщает после запуска скрипта, я получаю сообщение, что такого процесса нет; но сервер все еще работает.

Как мне получить правильный pid для сервера или, в более общем смысле, как мне остановить сервер из скрипта?

import os
import requests
from time import sleep

# Start server, in background.
print("Starting server...")
os.system('python -m http.server &')
# Make sure server has a chance to start before making request.
sleep(1)

print "Server pid: "
os.system('echo $$')

url = 'http://localhost:8000/index.html'
print("Testing request: ", url)
r = requests.get(url)
print("Status code: ", r.status_code)

person japhyr    schedule 24.10.2013    source источник
comment
Вы можете использовать subprocess.Popen вместо os.system, он предлагает множество дополнительных функций, включая завершение порожденного подпроцесса. Или вы можете просто import SimpleHTTPServer использовать его прямо в своем скрипте...   -  person l4mpi    schedule 24.10.2013
comment
Это полезно, но не могли бы вы сказать немного больше? Единственные ссылки, которые я нашел об использовании SimpleHTTPServer, говорят об использовании его из командной строки; Я не совсем уверен, как остановить и запустить сервер из скрипта Python. Я также никогда раньше не использовал процессы, поэтому я не совсем уверен, как запустить подпроцесс сервера, а затем остановить его. Активно гуглил...   -  person japhyr    schedule 24.10.2013
comment
В subprocess документации есть вся необходимая информация, см. разделы о Popen конструктор и используя объекты Popen - вы можете сделать что-то вроде server = Popen(["python", "-m", "SimpleHTTPServer"]), а затем использовать server.terminate() или server.kill() для завершения процесса. Что касается запуска SimpleHTTPServer в скрипте, просто посмотрите на блок if __name__ == "__main__": в SimpleHTTPServer.py — просто сохраните ссылку на экземпляр BaseServer и закройте его (это подкласс TCPServer, поэтому документы TCPServer должны помочь).   -  person l4mpi    schedule 24.10.2013


Ответы (8)


Вот что я делаю:

import threading

try: 
    from http.server import HTTPServer, SimpleHTTPRequestHandler # Python 3
except ImportError: 
    from SimpleHTTPServer import BaseHTTPServer
    HTTPServer = BaseHTTPServer.HTTPServer
    from SimpleHTTPServer import SimpleHTTPRequestHandler # Python 2

server = HTTPServer(('localhost', 0), SimpleHTTPRequestHandler)
thread = threading.Thread(target = server.serve_forever)
thread.daemon = True
thread.start()

def fin():
    server.shutdown()

print('server running on port {}'.format(server.server_port))

# here is your program

Если вы вызовете fin в своей программе, то сервер выключится.

person User    schedule 24.10.2013
comment
В настоящее время я использую Python 2, но мне бы хотелось, чтобы это работало и на Python 3. Я получил сообщение об ошибке «Нет модуля с именем HTTPServer», поэтому я изменил импорт Python 2 на from BaseHTTPServer import HTTPServer. Импорт работал, но затем я получил ошибку, что __init__() получил неожиданный ключевой аргумент «демон». Я получаю это, если я использую свою собственную версию этого скрипта, или если я просто скопирую ваш скрипт и исправлю импорт. Какие-либо предложения? - person japhyr; 25.10.2013
comment
Я исправил аргумент демона с помощью дополнительной строки. Надеюсь, теперь это должно работать под Python 3 и 2. - person User; 26.10.2013
comment
Вы можете убить сервер с помощью Ctrl-C? - person Ciro Santilli 新疆再教育营六四事件ۍ 05.08.2016
comment
@CiroSantilli巴拿馬文件六四事件法轮功 Поскольку для параметра deamon установлено значение true, программа должна завершиться после завершения основного потока. Обычно основной поток можно завершить с помощью Control+C. - person User; 30.08.2016
comment
@User Я не воспроизводил на Ubuntu 16.04, Python 2.7, терминал gnome. На Ctrl+C ничего не происходит, сервер просто продолжает работать, и мне нужно закрыть терминал, чтобы он остановился. - person Ciro Santilli 新疆再教育营六四事件ۍ 31.08.2016
comment
@CiroSantilli烏坎事件2016六四事件法轮功 Существует редактирование, которое указывает на проблему. демон. Теперь я обновил код, и он должен снова работать для Python 2 и 3. - person User; 05.12.2016

Небольшая модификация пользовательского кода выше:

import threading
try: 
  from http.server import HTTPServer, BaseHTTPRequestHandler # Python 3
except ImportError: 
  import SimpleHTTPServer
  from BaseHTTPServer import HTTPServer # Python 2
  from SimpleHTTPServer import SimpleHTTPRequestHandler as BaseHTTPRequestHandler
server = HTTPServer(('localhost', 0), BaseHTTPRequestHandler)
thread = threading.Thread(target = server.serve_forever)
thread.deamon = True
def up():
  thread.start()
  print('starting server on port {}'.format(server.server_port))
def down():
  server.shutdown()
  print('stopping server on port {}'.format(server.server_port))
person Andrew Stewart    schedule 11.02.2015

Это закрытое решение проблемы. Работает на питоне 3.

import os
import threading
import webbrowser
from http.server import HTTPServer, SimpleHTTPRequestHandler


def simple_http_server(host='localhost', port=4001, path='.'):

    server = HTTPServer((host, port), SimpleHTTPRequestHandler)
    thread = threading.Thread(target=server.serve_forever)
    thread.deamon = True

    cwd = os.getcwd()

    def start():
        os.chdir(path)
        thread.start()
        webbrowser.open_new_tab('http://{}:{}'.format(host, port))
        print('starting server on port {}'.format(server.server_port))

    def stop():
        os.chdir(cwd)
        server.shutdown()
        server.socket.close()
        print('stopping server on port {}'.format(server.server_port))

    return start, stop

simple_http_server, который вернет функции start и stop

>>> start, stop = simple_http_server(port=4005, path='/path/to/folder')

который вы можете использовать как

>>> start()
starting server on port 4005

127.0.0.1 - - [14/Aug/2016 17:49:31] "GET / HTTP/1.1" 200 -

>>> stop()
stopping server on port 4005
person Levon    schedule 14.08.2016


Вот контекстная версия, которую я предпочитаю, потому что она очищается автоматически, и вы можете указать каталог для обслуживания:

from contextlib import contextmanager
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from threading import Thread


@contextmanager
def http_server(host: str, port: int, directory: str):
    server = ThreadingHTTPServer(
        (host, port), partial(SimpleHTTPRequestHandler, directory=directory)
    )
    server_thread = Thread(target=server.serve_forever, name="http_server")
    server_thread.start()

    try:
        yield
    finally:
        server.shutdown()
        server_thread.join()


def usage_example():
    import time

    with http_server("127.0.0.1", 8087, "."):
        # now you can use the web server
        time.sleep(100)
person Tom Pohl    schedule 06.05.2021

Мое решение с открытием браузера:

Файл: http.py

import SimpleHTTPServer
import SocketServer
import threading
import webbrowser
import platform
from socket import SOL_SOCKET,SO_REUSEADDR

class HTTPServer():

    def __init__(self,port=8000,url='http://localhost'):
        self.port = port
        self.thread = None
        self.httpd = None                
        self.run = False
        self.url = url

        os = platform.system()
        if os=='Linux':
            self.browser_path = "/usr/bin/google-chrome %s"            
        elif os == 'Windows':
            self.browser_path = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s"   
        else:
            print("Chrome not found!")


    def start(self):        
        self.run = True     
        self.httpd = SocketServer.TCPServer(("", self.port), SimpleHTTPServer.SimpleHTTPRequestHandler)
        self.httpd.socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self.thread = threading.Thread(target = self._serve)
        self.thread.start()
        webbrowser.get(str(self.browser_path)).open(self.url+":"+str(self.port)+"/")


    def _serve(self):        
        while self.run:
            self.httpd.handle_request()

    def stop(self):
        self.run = False
        self.httpd.server_close()

После этого просто запустите:

from http import HTTPServer

server = HTTPServer()
server.start()

raw_input("Enter to close")

server.stop()
person heltonitba    schedule 03.09.2015
comment
Вместо открытия Chrome вы можете использовать start %s в Windows и open %s в OSX (не уверен в Linux), чтобы открыть браузер по умолчанию. - person Josep Valls; 18.02.2017

На мой взгляд, что я сделал:

  1. перейти к монитору активности
  2. затем перейдите в сеть
  3. поиск слова "питон"

(только если вы запустили команду cmd/terminal в python, потому что я думаю, что способ остановить ее в cmd/terminal — это ctrl+c или просто выйти из cmd/terminal)

примечание: pid тоже есть

  1. выйти из процесса «python» (если это не так, используйте процесс принудительного выхода)
  2. если это работает в cmd/терминале, то все готово! наслаждайся~

Надеюсь, это поможет: D!!

person Dunno dotcom    schedule 24.11.2019
comment
И как это внутренний подход? - person ZF007; 24.11.2019
comment
хорошо, у меня такая же проблема, как у вас, поэтому я искал, что такое PID в google, и показывает результат в google следующим образом: google.com/, то у меня есть представление о том, бросить его, то это работает лол - person Dunno dotcom; 25.11.2019
comment
Ваш подход, по сути, дает результат через внешний принудительный процесс. Суть здесь в том, что OP запрашивает решение из серверного скрипта. Это можно сделать с помощью потоковой обработки или новейших асинхронных методов. У меня нет этой проблемы, и я просто просмотрел ваш ответ, поскольку он был помечен как ответ низкого качества ... и решил, нужно ли его удалять или нет. Я надеюсь, что мой комментарий поможет вам еще раз внимательно взглянуть на вопрос и переоценить, дает ли ваш ответ правильное решение, о котором просил ОП. - person ZF007; 25.11.2019
comment
Хорошо я понял :) - person Dunno dotcom; 25.11.2019

Использование Python 3.8

import http.server
import socketserver
import threading
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
server = socketserver.TCPServer(("", PORT), Handler)
thread = threading.Thread(target = server.serve_forever)
thread.daemon = True
thread.start()
person Aman Kejriwal    schedule 30.07.2020