2015-01-09 46 views
4

我有一個腳本,它在一個線程中設置了一個BasicHTTPServer,以便主腳本可以自動打開指向服務器url的Web瀏覽器來下載文件。文件下載後,我想關閉該服務器,但我不知道如何去做。這是我目前所做的一個例子:從另一個線程關閉Python BasicHTTPServer

def server(): 
    HandlerClass = SimpleHTTPRequestHandler 
    ServerClass = BaseHTTPServer.HTTPServer 
    Protocol = 'HTTP/1.0' 

    server_address = ('127.0.0.1', 8000) 
    HandlerClass.protocol_version = Protocol 
    httpd = ServerClass(server_address, HandlerClass) 
    httpd.serve_forever() 

def download(): 
    t = threading.Thread(name='server', target=server) 
    t.start() 
    webbrowser.open('safari-http://127.0.0.1:8000/') 

我想在webbrowser.open()後關閉服務器。

謝謝

+0

https://docs.python.org/2/library/socketserver.html#SocketServer.BaseServer.shutdown –

+0

只是想指出,我所知道的BaseServer.shutdown()方法,但我有不知道如何在這種情況下實施它。 – HeyItsJono

+0

不幸的是,不行。說沒有全局變量httpd。在server()函數之外移動除「httpd.serve_forever()」之外的所有內容只會在調用download()時使程序掛起。 – HeyItsJono

回答

0

所以通過多篇文章深挖後我設法找到一種爲我的作品,其完全關閉服務器雜亂的解決方案。要做到這一點我納入從下列來源代碼:

UI是獨家的iOS版的Python IDE Pythonista一個模塊,它基本上只是創建按鈕 「開始」,「停止「和」訪問「,它們綁定到各自的_t函數。 ui.in_background修飾器只是讓ui在後臺發生事件時保持響應。 self.httpd.socket.close()是真正關閉服務器的東西,但它很混亂,並向stdout/err輸出一個醜陋的錯誤,所以我別無選擇,只能通過將stdout/err重定向到一個死類來取消它,以便使錯誤消失。標準stdout/err行爲在之後立即恢復。感謝大家花時間和精力來幫助我,我非常感謝。

import console 
import BaseHTTPServer 
import SocketServer 
from SimpleHTTPServer import SimpleHTTPRequestHandler 
import sys 
import threading 
import webbrowser 
from time import sleep 
import ui 

original_stdout = sys.stdout 
original_stderr = sys.stderr 


class BasicServer(SocketServer.TCPServer): 
    allow_reuse_address = True 

class NullifyOutput(): 
    def write(self, s): 
     pass 

class ServerThread(threading.Thread): 
    def __init__(self, ip, port): 
     super(ServerThread, self).__init__() 
     self.ip = ip 
     self.port = port 
     self.HandlerClass = SimpleHTTPRequestHandler 
     self.Protocol = 'HTTP/1.0' 
     self.server_address = (self.ip, self.port) 
     self.HandlerClass.protocol_version = self.Protocol 
     try: 
      self.httpd = BasicServer(self.server_address, self.HandlerClass) 
     except: 
      self.port += 1 
      self.server_address = (self.ip, self.port) 
      self.httpd = BasicServer(self.server_address, self.HandlerClass) 
     self.stoptheserver = threading.Event() 


    def run(self): 
     while not self.stoptheserver.isSet(): 
      self.httpd.handle_request() 


    def join(self, timeout=None): 
     self.stoptheserver.set() 
     self.httpd.socket.close() 
     super(ServerThread, self).join(timeout) 


server = ServerThread('127.0.0.1', 8000) 

def start_t(sender): 
    print server.isAlive() 
    if not server.isAlive(): 
     server.start() 


def visit_t(sender): 
    webbrowser.open('http://127.0.0.1:' + str(server.port)) 
    #webbrowser.open('safari-http://127.0.0.1' + str(server.port)) 
    # Use the safari- prefix to open in safari. You may need to switch to 
    # pythonista then back to safari to get the page to load. 

@ui.in_background 
def stop_t(sender): 
    sys.stdout, sys.stderr = NullifyOutput(), NullifyOutput() 
    server.join(3) 
    sys.stdout, sys.stderr = original_stdout, original_stderr 

ui.load_view('SimpleServer').present('sheet') 
0

這裏是cryptoassets.core project, status server一個例子:

class StatusHTTPServer(threading.Thread): 

    def __init__(self, ip, port): 
     threading.Thread.__init__(self) 
     self.running = False 
     self.ready = False 
     self.ip = ip 
     self.port = port 

    def run(self): 
     self.running = True 
     self.ready = True 
     self.httpd.serve_forever() 
     self.running = False 

    def start(self): 
     server_address = (self.ip, self.port) 
     try: 
      self.httpd = HTTPServer(server_address, StatusGetHandler) 
     except OSError as e: 
      raise RuntimeError("Could not start cryptoassets helper service status server at {}:{}".format(self.ip, self.port)) from e 

     threading.Thread.start(self) 

    def stop(self): 
     if self.httpd and self.running: 
      self.httpd.shutdown() 
      self.httpd = None 
+0

因此,任何這樣的實例將運行在一個單獨的線程中,我可以從任何地方調用stop()來停止它? – HeyItsJono

+0

@HeyItsJono:是的,就是這麼多。 –

+0

不幸的是,這仍然無法正常工作。調用stop()成功,但服務器本身並不實際停止,所以http.shutdown()由於某種原因不起作用。 – HeyItsJono

1

我試圖給here的例子。你能檢查它是否適合你。

runFlag = True 
def server(server_class=BaseHTTPServer.HTTPServer, 
        handler_class=BaseHTTPServer.BaseHTTPRequestHandler): 
    global runFlag 
    server_address = ('127.0.0.1', 8000) 
    HandlerClass.protocol_version = Protocol 
    httpd = ServerClass(server_address, HandlerClass) 
    while runFlag: 
     httpd.handle_request() 
    httpd.shutdown() 

def download(): 
    t = threading.Thread(name='server', target=server) 
    t.start() 
    webbrowser.open('https:\\www.google.com') 
    global runFlag 
    runFlag = False 
+0

感謝您的幫助,這似乎工作,在runFlag更改爲False服務器停止提供請求後,但是當我嘗試再次運行該腳本時,我會收到錯誤:_ [Errno 48]已在使用中的地址_表示某些內容仍在捆綁地址。所以服務器大部分都停止了,但沒有釋放地址或端口。任何想法如何解決這個問題? – HeyItsJono

+0

也有沒有什麼辦法去解決這個問題,而不使用全局變量。我讀過的所有東西都告訴我要遠離它們。 – HeyItsJono

+0

@HeyItsJono對不起,因爲我沒有在週末玩電腦。 '錯誤:48'有一個解決方案在這裏http://stackoverflow.com/a/19071568/2382792 它很好,你已經發布的解決方案! –