SocketServer
类的继承关系
编程接口
#BaseServer代码 class BaseServer: def __init__(self, server_address, RequestHandlerClass): """Constructor. May be extended, do not override.""" self.server_address = server_address self.RequestHandlerClass = RequestHandlerClass self.__is_shut_down = threading.Event() self.__shutdown_request = False def finish_request(self, request, client_address):#处理请求的方法 """Finish one request by instantiating RequestHandlerClass.""" self.RequestHandlerClass(request, client_address, self)#RequestHandlerCLass构造
#BaserequestHandler要子类覆盖的方法 class BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish() def setup(self):#每一个连接初始化 pass def handle(self):#每一个处理请求 pass def finish(self):#每一个连接清理 pass
#测试代码 import socketserver import threading class MyHandler(socketserver.BaseRequestHandler): def handle(self): # super().handle()#可以不调用,父类handler什么都没有做 print('-'*30) print(self.server)#服务 print(self.request)#服务端连接请求的socket对象 print(self.client_address)#客户端地址 print(self.__dict__) print(self.server.__dict__) print(threading.enumerate()) print(threading.current_thread()) print('*'*30) addr = ('10.39.27.2',9999) server = socketserver.ThreadingTCPServer(addr,MyHandler) server.serve_forever()#永久
import threading import logging import socketserver FORMAT="%(asctime)s %(threadName)s %(thread)d %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT) class MyHandler(socketserver.BaseRequestHandler): def handle(self): print(self.request)#服务端负责客户端连接请求的socket对象 print(threading.enumerate()) print(threading.current_thread()) for i in range(3): data = self.request.recv(1024) logging.info(data) logging.info('========end===========') addr = ('10.39.27.2',9999) # server = socketserver.ThreadingTCPServer(addr,MyHandler) server = socketserver.TCPServer(addr,MyHandler) server.serve_forever()
小结
创建服务器需要几个步骤: 1.从BaseRequestHandler类派生出子类,并覆盖其handler()方法来创建请求处理程序类,此方法将处理传入请求; 2.实例化一个服务器类,传参服务器的地址和请求处理类; 3.调用服务器示例的handler_request()或server_forver()方法; 4.调用server_close()关闭套接字。
实现EchoServer
import threading from socketserver import ThreadingTCPServer,BaseRequestHandler import sys class EchoHandler(BaseRequestHandler): def setup(self): super().setup() self.event = threading.Event()#初始工作 def handle(self): super().handle() while not self.event.is_set(): data = self.request.recv(1024).decode() msg = "{} {}".format(self.client_address,data).encode() self.request.send(msg) print('End') def finish(self): super().finish() self.event.set() addr = ('0.0.0.0',9999) server = ThreadingTCPServer(addr,EchoHandler) server_thread =threading.Thread(target=server.serve_forever,name='EchoServer',daemon=True) server_thread.start() try: while True: cmd = input('>>>') if cmd.strip() == 'quit': break print(threading.enumerate()) except Exception as e: print(e) except KeyboardInterrupt: pass finally: print('exit') sys.exit(0)
练习--改写ChatServer
import threading from socketserver import ThreadingTCPServer,BaseRequestHandler import sys import logging FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT) class ChatHandler(BaseRequestHandler): clients = {} def setup(self): super().setup() self.event = threading.Event() self.clients[self.client_address] =self.request def handle(self): super().handle() while not self.event.is_set(): data = self.request.recv(1024).decode() if data == 'quit': break msg = "{} {}".format(self.client_address,data).encode() logging.info(msg) for c in self.clients.values(): c.send(msg) print('End') def finish(self): super().finish() self.clients.pop(self.client_address) self.event.set() addr = ('0.0.0.0',9999) server = ThreadingTCPServer(addr,ChatHandler) server_thread = threading.Thread(target=server.serve_forever,name='ChatServer',daemon=True) server_thread.start() try: while True: cmd = input('>>>') if cmd.strip() == 'quit': break print(threading.enumerate()) except Exception as e: print(e) except KeyboardInterrupt: pass finally: print('exit') sys.exit(0)
解决客户端主动断开连接问题
import threading from socketserver import ThreadingTCPServer,BaseRequestHandler import sys import logging FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT) class ChatHandler(BaseRequestHandler): clients = {} def setup(self): super().setup() self.event = threading.Event() self.clients[self.client_address] =self.request def handle(self): super().handle() while not self.event.is_set(): data = self.request.recv(1024).decode() print(data,'!!!!!!!!!!!!!!!!!!!!!')#增加 if data == 'quit': break msg = "{} {}".format(self.client_address,data).encode() logging.info(msg) for c in self.clients.values(): c.send(msg) print('###############')#增加 print('End') def finish(self): super().finish() self.clients.pop(self.client_address) self.event.set() addr = ('0.0.0.0',9999) server = ThreadingTCPServer(addr,ChatHandler) server_thread = threading.Thread(target=server.serve_forever,name='ChatServer',daemon=True) server_thread.start() try: while True: cmd = input('>>>') if cmd.strip() == 'quit': break print(threading.enumerate()) except Exception as e: print(e) except KeyboardInterrupt: pass finally: print('exit') sys.exit(0)
#修改上述代码中handler()函数的一行代码即可 将if data =='quit' 修改为 if not data or data =='quit'
总结