class NetworkServerBase: def __init__(self, port): self.host = "0.0.0.0" self.port = port self.server_fd = None self.state = config.SERVER_STOP self.logger = Log() def _close_fd(self): try: self.server_fd.shutdown(socket.SHUT_RDWR) self.server_fd.close() except IOError as e: self.logger.error("net socket close fail err: " + str(e.errno) + " " + e.strerror) def _network_start(self): self.server_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: self.server_fd.bind((self.host, self.port)) except IOError as e: self._close_fd() self.logger.error("server bind fail. msg: " + str(e.errno) + " " + e.strerror) return self.server_fd.listen(config.MAX_LISTEN_QUEUE_SIZE) self.server_fd.setblocking(False) self.port = self.server_fd.getsockname()[1] self.state = config.SERVER_ESTABLISHED self.logger.info("server established. port:" + str(self.port))
class Connection: err_d = (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK) err_conn = (errno.EISCONN, 10057, 10035) # client 10053 def __init__(self, workers): self.client_fd = None self.recv_buf = '' self.send_buf = '' self.conn_id = None self.msg = Message() self.logger = Log() self.workers = workers def close_fd(self): try: self.logger.debug( "client exit. fd = " + str(self.client_fd) + "port = " + str(self.client_fd.getpeername()[1])) self.client_fd.shutdown(socket.SHUT_RDWR) self.client_fd.close() except IOError as err: self.logger.error("conn socket close fail err:" + str(err.errno)) def assign(self, fd, conn_id): self.client_fd = fd self.client_fd.setblocking(False) self.client_fd.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) self.conn_id = conn_id self.logger.debug("new client. fd = " + str(self.client_fd) + "port = " + str(self.client_fd.getpeername()[1])) def _package_message(self): while len(self.recv_buf) != 0: size = self.msg.recv(self.recv_buf) self.recv_buf = self.recv_buf[size:] if self.msg.finish(): # self.logger.debug("recv msg:" + self.msg.__str__()) # print "recv msg:" + self.msg.__str__() self.workers.message_handler(self.conn_id, self.msg) self.msg.assign() def recv_event(self): text = '' # 客户端退出 not text为 True,这里text上空字符串。 # 如果是客户端暂时没有数据,并不会导致text为空传,导致10035异常,非阻塞模式中 try: text = self.client_fd.recv(1024) if not text: err_code = 10000 self.close_fd() return True except socket.error, (code, strerror): if code not in Connection.err_d: err_code = code self.close_fd() return True self.recv_buf += text self._package_message() return False
class Server: def __init__(self, name, uuid): self.os_name = platform.system() self.python_version = platform.python_version().split(".")[0] self.server_name = name self.server_id = uuid self.network_server = None self.work_process = None self.logger = Log() self.conf_loader = ConfigLoader() def add_handler(self, handler_func): try: self.work_process.add_handler(handler_func.handler_id, handler_func) self.logger.info("add handler " + str(handler_func.handler_id)) except Exception as e: self.logger.error("work process not init." + e.message) # 预选择服务器IO模式 epoll有bug,连接无法安全断开. select实测没light快 囧。。。 def pre_bind_io_mode(self, port, mode): if not isinstance(mode, str): return False if mode.__eq__("epoll") and hasattr(select, 'epoll'): self.network_server = Epoll(port) self.logger.info("network mode epoll") return True if mode.__eq__("epoll_et") and hasattr(select, 'epoll'): self.network_server = Epoll(port, use_et=True) self.logger.info("network mode epoll et") return True if mode.__eq__("select") and hasattr(select, 'select'): self.network_server = Select(port) self.logger.info("network mode select") return True if mode.__eq__("light"): self.network_server = LightServer(port) self.logger.info("network mode light server") return True return False def start(self, port=None, mode=None): if port is None: port = self.conf_loader.get_int("port", 0) if not self.pre_bind_io_mode(port, mode): if hasattr(select, 'epoll'): self.network_server = Epoll(port) self.logger.info("network mode epoll lt") elif hasattr(select, 'select'): self.network_server = Select(port) self.logger.info("network mode select") else: self.network_server = LightServer(port) self.logger.info("network mode light server") self.work_process = WorkerPool(mode="light") # light, multi self.network_server.init(self.work_process) self.work_process.init(self.network_server.conn_pool, 4) self.network_server.start() def run(self): if self.network_server is None: self.logger.error("server instance is None") return if self.network_server.state == SERVER_ESTABLISHED: self.work_process.start() self.network_server.run() def stop(self): self.work_process.stop()