2012-11-21 62 views
2

我正在使用下面的代码片段在Python中编写HTTP服务器。服务器运行良好,直到发生一些IOError导致它重新启动。由于服务器启动正常,但重新启动处理出错,但之后不接受任何请求。在Python中重新启动HTTP服务器的正确方法

这段代码有什么问题吗?

#!/bin/python 
from BaseHTTPServer import HTTPServer 
import json 
import config 
import time 
import socket 
from SimpleHTTPServer import SimpleHTTPRequestHandler 
from SocketServer import BaseServer 


class MyHandler(SimpleHTTPRequestHandler): 
    def parseArgs(self): 
     args = {} 
     try: 
      config.logging.info(self.path) 
      args_list = self.path.split("?")[1].split("&") 
      for entry in args_list: 
       args[entry.split("=")[0]] = entry.split("=")[1] 
     except IndexError: 
      pass 
     return args 

    def do_GET(self): 
     try: 
     response = {} 
     args = self.parseArgs() 
     config.logging.debug("Handle the request") 
     self._handle_request(args, response) 
     config.logging.debug("Write the header back to the client.") 
     self.send_response(200) 
     self.send_header('Access-Control-Allow-Origin', '*') 
     self.send_header('Content-Type:', 'application/json; charset=UTF-8') 
     self.end_headers() 
     config.logging.debug("Finish writing the header and start writing JSON response.") 
     json_encoded = json.dumps(response) 
     config.logging.debug(json_encoded) 
     self.wfile.write(json_encoded) 
     config.logging.debug("JSON Response written successfully.") 
     except Exception as e: 
     config.logging.exception('Exception occurs when writing back the response.') 
     return 

    def _handle_request(self, args, response): 
     try: 
     response["sysTime"] = long(round(time.time() * 1000)) 
     if not "cmd" in args: 
      response["message"] = "Error: No command provided." 
     else: 
      response["message"] = args['cmd'] 
     except Exception as e: 
      response["message"] = "Error: Exception occurs (check logs)." 
      config.logging.exception('Exception occurs when handling request.') 

    def do_POST(self): 
     self.send_response(200) 
     self.send_header('Content-type',  'text/html') 
     self.end_headers() 
     self.wfile.write("Nothing here :(") 

def main(): 
    while True: 
    try: 
     httpd = HTTPServer(('', config.listening_port), MyHandler) 
     sa = httpd.socket.getsockname() 
     msg = "Serving HTTP on " + sa[0] + " port " + str(sa[1]) + "..." 
     print msg 
     config.logging.info(msg) 
     httpd.serve_forever() 
    except KeyboardInterrupt: 
     print '^C received, shutting down server' 
     config.logging.info('^C received, shutting down server') 
     httpd.socket.close() 
     break 
    except Exception as e: 
     httpd.shutdown() 
     httpd.socket.close() 
     print "Error occurs. Retry in 5 seconds" 
     config.logging.exception('Exception occurs. Retry in 5 seconds.') 
     time.sleep(5) 

if __name__ == '__main__': 
    main() 

对不起,错过了模块配置。

import logging 

# global variables 
listening_port = 9001 
logging.basicConfig(filename='error.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 

运行此操作的一个网址是http://localhost:9001/?cmd=some_command。只需在服务器启动后将其粘贴到任何浏览器中即可。

编辑:

我想这事做与KVM或它被设定为我公司的机器上的方式。由于我的服务器运行在只能通过ssh访问的KVM上,每次退出ssh会话时,调用上面的url命令(在chrome中),等到chrome通知没有连接,返回到ssh会话,调用url再次发出命令,错误发生了。

我把调试消息放在do_GET()中的写入响应之间self.send_response(200)。当发生异常时,这是我得到的踪迹。我猜这跟log_message里面的sys.stderr.write有关。

11/23/2012 10:58:29 AM - INFO - Handle the request 
11/23/2012 10:58:29 AM - INFO - /?cmd=get_info&uid=pp 
11/23/2012 10:58:29 AM - INFO - Write the header back to the client. 
11/23/2012 10:58:29 AM - ERROR - Exception occurs when writing back the response. 
Traceback (most recent call last): 
    File "service.py", line 57, in do_GET 
     self.send_response(200) 
    File "/usr/lib/python2.7/BaseHTTPServer.py", line 385, in send_response 
     self.log_request(code) 
    File "/usr/lib/python2.7/BaseHTTPServer.py", line 422, in log_request 
     self.requestline, str(code), str(size)) 
    File "/usr/lib/python2.7/BaseHTTPServer.py", line 458, in log_message 
     format%args)) 
    IOError: [Errno 5] Input/output error 

编辑:

问题就走了,当我重写log_message()什么也不做。我知道这只是隐藏了问题,但至少它暂时对我有用。

+5

你有没有考虑过使用[Flask](http://flask.pocoo.org/)?那么你不必担心这些东西...... –

+1

或[gunicorn](http://gunicorn.org/)。 – syrion

+1

当我尝试它时,您的代码有效:服务器在5秒后重新启动并再次接受连接。但是为了伪造失败,我不得不破解SocketServer.py,因为我无法从serve_forever()中获得异常。你需要发布一个让我们先重现问题的例子。 –

回答

0

sys.stderr将消息写入标准输出,通常是启动程序的shell控制台。所以如果shell控制台被关闭,sys.stderr.writes会引发IO Error。

所以这个问题的根本原因是log_message()函数中的sys.stderr.write试图写一条消息到ssh shell控制台(标准输出),你最初启动你的python程序的地方,所以如果你保留ssh会话还活着,这个问题不会发生。但是,如果退出原始ssh会话,shell控制台会关闭,那么sys.stderr.write将无法将消息写入原始控制台,然后发生IO错误.... log_message通常会写入如下内容:

127.0.0.1 - - [01/Dec/2015 20:16:32] "GET/HTTP/1.1" 200 - 

所以解决的办法就是用标准输出重定向到/ dev/null的如下运行Python脚本:

python your_script.py > /dev/null 2>&1 & 

Holp它帮助。