Python TCPServer Timout套接字超时处理

时间:2014-07-15 18:58:28

标签: python sockets tcpserver

我正在尝试使用TCPServer处理难以复制的错误案例。我们已经看到一些事件,当处理程序中发生套接字超时时,代码永远不会恢复并继续返回socket.timeout异常。 这看起来来自Socket.py库代码中的以下片段:

def readinto(self, b):
    """Read up to len(b) bytes into the writable buffer *b* and return
    the number of bytes read.  If the socket is non-blocking and no bytes
    are available, None is returned.

    If *b* is non-empty, a 0 return value indicates that the connection
    was shutdown at the other end.
    """
    self._checkClosed()
    self._checkReadable()
    if self._timeout_occurred:
        raise OSError("cannot read from timed out object")
    while True:
        try:
            return self._sock.recv_into(b)
        except timeout:
            self._timeout_occurred = True
            raise
        except InterruptedError:
            continue
        except error as e:
            if e.args[0] in _blocking_errnos:
                return None
            raise

一旦发生超时_timeout_occurred设置为True,并且下一次进入此函数,套接字已设置标志,并将立即退出,无法从超时对象中读取错误。

现在代码使用TCP Server(仅包含相关代码)基本上它是从套接字中读取内容,并将其排队以便单独处理。

def get_event(file_):
    pre_package_len = 8
    msg = file_.read(pre_package_len)
    if len(msg) == pre_package_len:
        pkg = PRE_PACKAGE_FRAME.unpack(msg)
        msg = file_.read(pkg['len'])
        logger.debug('recv: type: %s len: %s bytes read: %s',
                     pkg['type'], pkg['len'], len(msg))
        if len(msg) >= pkg['len']:
            if pkg['type'] == cdefs.kNotification:
                e = EVENT_FRAME.unpack(msg)
                return decode_event(e)
            logger.warn('received unsupported package type: %s', pkg['type'])
    else:
        logger.error('failed to recv')

class _EventHandler(StreamRequestHandler):
    def handle(self):
        logger.debug("Got event from %s", self.client_address)
        try:
            e = get_event(self.rfile)
            if e:
                self.q.put(e)
        except socket.timeout:
            logger.error('timed out reading event')

def process_event(q, handler, shutdown_sentinel):
    for e in iter(q.get, shutdown_sentinel):
        try:
            handler(e)
        except Exception:
            logger.exception('Unhandled exception handling event: %s', e)
    logger.info('exiting')

def eventhandler_maker(q, timeout):
    return type('NewEventHandler',
                (_EventHandler, object),
                dict(q=q, timeout=timeout))

def process_events(handler, address, timeout=20):
    sentinel = object()
    q = Queue()
    eventhandler = eventhandler_maker(q, timeout)
    server = TCPServer(address, eventhandler)
    start_thread(server.serve_forever)
    start_thread(process_event, (q, handler, sentinel))

    def shutdown():
        logger.info('shutting down')
        q.put(sentinel)
        server.shutdown()

    def add_event(e):
        q.put(e)

    return shutdown, add_event

症状是一旦超时发生,日志会一直显示“超时读取事件”,代码再也不会执行任何操作了。我添加了代码来转储server.socket.gettimeout()和socket.getdefaulttimeout(),并且都返回None。该应用程序在带有python 3.4.0的嵌入式Linux 3.10内核上运行。

我在这里有两个问题:

  1. 这里有什么好的恢复策略?关闭()/关闭()服务器套接字然后重新启动它?或者有更好的策略吗?
  2. 是否有一个好的第三方工具可以引发超时,因此可以证明恢复策略是正确的?

0 个答案:

没有答案