zoukankan      html  css  js  c++  java
  • 网络编程---SocketServer

    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'

    总结

    做一枚奔跑的老少年!
  • 相关阅读:
    Ajax函数
    javascript 重定向和打开新窗口(ZZ)
    asp.net 学习
    dojo杂谈
    Deciding between COALESCE and ISNULL in SQL Server
    从 Twitter 运维技术经验可以学到什么
    重新安装ASP.NET命令
    SQL Server 2008中新增的变更数据捕获(CDC)和更改跟踪
    SQL Server 2005/2008/2012中应用分布式分区视图
    数据库运维原则
  • 原文地址:https://www.cnblogs.com/xiaoshayu520ly/p/11006131.html
Copyright © 2011-2022 走看看