为了实现TCPServer的功能,定义一个类用于继承TCPServer并实现handle_stream方法。HttpServer就是一个很好的例子。
13.1 构造函数
def __init__(self, io_loop=None, ssl_options=None, max_buffer_size=None, read_chunk_size=None): self.io_loop = io_loop self.ssl_options = ssl_options self._sockets = {} # fd -> socket object self._pending_sockets = [] self._started = False self.max_buffer_size = max_buffer_size self.read_chunk_size = read_chunk_size # Verify the SSL options. Otherwise we don't get errors until clients # connect. This doesn't verify that the keys are legitimate, but # the SSL module doesn't do that until there is a connected socket # which seems like too much work if self.ssl_options is not None and isinstance(self.ssl_options, dict): # Only certfile is required: it can contain both keys if 'certfile' not in self.ssl_options: raise KeyError('missing key "certfile" in ssl_options') if not os.path.exists(self.ssl_options['certfile']): raise ValueError('certfile "%s" does not exist' % self.ssl_options['certfile']) if ('keyfile' in self.ssl_options and not os.path.exists(self.ssl_options['keyfile'])): raise ValueError('keyfile "%s" does not exist' % self.ssl_options['keyfile'])
实现流程如下:
(1) 设置属性。
(2) 判断是否支持SLL,如果支持,判断证书文件以及秘钥文件是否存在。
13.2 监听 listen
开启指定端口的接收连接。
为了监听多个端口时,这个方法可能会被调用多次。这个方法会立即起作用,不需要调用TCPServer.start方法。但是,还是有必要启动IOLoop。
def listen(self, port, address=""): """Starts accepting connections on the given port. This method may be called more than once to listen on multiple ports. `listen` takes effect immediately; it is not necessary to call `TCPServer.start` afterwards. It is, however, necessary to start the `.IOLoop`. """ sockets = bind_sockets(port, address=address) self.add_sockets(sockets)
调用bind_sockets方法来获得sockets集合对象。调用add_sockets方法循环处理每一个sockets对象,主要注册socket建立连接后的处理回调函数。
13.3 添加sockets (add_sockets)
def add_sockets(self, sockets): """Makes this server start accepting connections on the given sockets. The ``sockets`` parameter is a list of socket objects such as those returned by `~tornado.netutil.bind_sockets`. `add_sockets` is typically used in combination with that method and `tornado.process.fork_processes` to provide greater control over the initialization of a multi-process server. """ if self.io_loop is None: self.io_loop = IOLoop.current() for sock in sockets: self._sockets[sock.fileno()] = sock add_accept_handler(sock, self._handle_connection, io_loop=self.io_loop)
针对每一个socket, 注册socket建立连接后的处理回调函数,回调函数为内部方法_handle_connection。
13.4 关闭服务器(stop)
def stop(self): """Stops listening for new connections. Requests currently in progress may still continue after the server is stopped. """ for fd, sock in self._sockets.items(): self.io_loop.remove_handler(fd) sock.close()
关闭服务器,停止监新的请求连接。在服务器关闭之后,当前正在处理的请求会继续执行。
执行逻辑就是,对服务器中所有的sockets对象,调用两个方法,一个是移除io_loop中的处理回调函数,一个是关闭socket.