zoukankan      html  css  js  c++  java
  • Python之socketserver

    import threading
    from socketserver import ThreadingTCPServer,BaseRequestHandler
    import sys
    import logging
    
    FORMAT = '%(asctime)s %(threadName)d %(thread)d %(message)s'
    logging.basicConfig(level=logging.INFO,format=FORMAT)
    
    class ChatHandler(BaseRequestHandler): #一对一,相当于receive函数
        clients = {}
    
        def setup(self):
            self.event = threading.Event()
            self.clients[self.client_address] = self.request
        def finish(self):
            self.clients.pop(self.client_address)
            self.event.set()
    
        def handle(self):
            print(self.request) #new_socket 用来recv
            while not self.event.is_set():
                data = self.request.recv(1024)
                print(data,self.client_address)
                msg = '{}.ack'.format(data).encode()
                #如何实现一对多,多在哪里,如何获得
                for c in self.clients.values():
                    c.send(msg)
    addr = ('0.0.0.0',9999)
    server = ThreadingTCPServer(addr,ChatHandler)  #相当于tcp总的socket
    print(server)
    t = threading.Thread(target=server.serve_forever,name='chatserver')
    t.start()
    try:
        while True:
            cmd = input(">>>")
            if cmd.strip() == 'quit':
                break
    except Exception as e:
        print(e)
    except KeyboardInterrupt:
        pass
    finally:
        print('exit')
        sys.exit(0)

     类的继承关系

    BaseServer------>TCPServer---------->UDPServer
                           |                  |
                   UnixStreamServer         UnixDatagramServer
    
    socketserver有四个同步类
    TCPServer,UDPAServer,UnixStreamServer,UnixDatagramServer
    2个mixin类,ForkingMixin,ThreadingMixin类用来支持异步
    
    class ForkingUDPServer(ForkingMixin,UDPServer):pass
    class ForkingTCPServer(ForkingMixin,TCPServer):pass
    class ThreadingUDPServer(ThreadingMixin,UDPServer):pass
    class ThreadingTCPServer(ThreadingMixin,TCPServer):pass
    fork创建多进程,thread是创建多线程
    
    BaseRequestHandler类
    它是用户连接的用户请求处理类的基类,定义为BaseRequestHandler(request,client_address,server)
    服务端server实例接收用户请求后,最后会实例化这个类
    它被实例化时,送入3个构建参数,request,client,address,server自身
    以后就可以在BaseRequestHandler类的实例上使用一下属性
    self.request是和客户端连接的socket对象
    self.server是tcpserver本身
    self.client_address是客户端的地址
    
    
    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
    
    class MyHandler(socketserver.BaseRequestHandler):#相当于socket的recv方法
        def handle(self):
            print(self.request) #new_socket
            print(self.client_address)  #('127.0.0.1', 62685)
            print(self.server)  #<socketserver.ThreadingTCPServer object at 0x033CFA50>
    
    server = socketserver.ThreadingTCPServer(('0.0.0.0',9999),MyHandler)
    print(server)  #<socketserver.ThreadingTCPServer object at 0x033CFA50>
    server.serve_forever()

     实现群聊

    import threading
    from socketserver import ThreadingTCPServer,BaseRequestHandler
    import sys
    import logging
    
    FORMAT = '%(asctime)s %(threadName)d %(thread)d %(message)s'
    logging.basicConfig(level=logging.INFO,format=FORMAT)
    
    class ChatHandler(BaseRequestHandler): #一对一,相当于receive函数
        clients = {}
    
        def setup(self):
            self.event = threading.Event()
            self.clients[self.client_address] = self.request
        def finish(self):
            self.clients.pop(self.client_address)
            self.event.set()
    
        def handle(self):
            print(self.request) #new_socket 用来recv
            while not self.event.is_set():
                data = self.request.recv(1024)
                print(data,self.client_address)
                msg = '{}.ack'.format(data).encode()
                #如何实现一对多,多在哪里,如何获得
                for c in self.clients.values():
                    c.send(msg)
    addr = ('0.0.0.0',9999)
    server = ThreadingTCPServer(addr,ChatHandler)  #相当于tcp总的socket
    print(server)
    t = threading.Thread(target=server.serve_forever,name='chatserver')
    t.start()
    try:
        while True:
            cmd = input(">>>")
            if cmd.strip() == 'quit':
                break
    except Exception as e:
        print(e)
    except KeyboardInterrupt:
        pass
    finally:
        print('exit')
        sys.exit(0)
     类的继承关系
    
    BaseServer------>TCPServer---------->UDPServer
                           |                  |
                   UnixStreamServer         UnixDatagramServer
    socketserver有四个同步类
    TCPServer,UDPAServer,UnixStreamServer,UnixDatagramServer
    2个mixin类,ForkingMixin,ThreadingMixin类用来支持异步
    
    class ForkingUDPServer(ForkingMixin,UDPServer):pass
    class ForkingTCPServer(ForkingMixin,TCPServer):pass
    class ThreadingUDPServer(ThreadingMixin,UDPServer):pass
    class ThreadingTCPServer(ThreadingMixin,TCPServer):pass
    fork创建多进程,thread是创建多线程
    BaseRequestHandler类
    它是用户连接的用户请求处理类的基类,定义为BaseRequestHandler(request,client_address,server)
    服务端server实例接收用户请求后,最后会实例化这个类
    它被实例化时,送入3个构建参数,request,client,address,server自身
    以后就可以在BaseRequestHandler类的实例上使用一下属性
    self.request是和客户端连接的socket对象
    self.server是tcpserver本身
    self.client_address是客户端的地址
    
    
    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
    
    class MyHandler(socketserver.BaseRequestHandler):#相当于socket的recv方法
        def handle(self):
            print(self.request) #new_socket
            print(self.client_address)  #('127.0.0.1', 62685)
            print(self.server)  #<socketserver.ThreadingTCPServer object at 0x033CFA50>
    
    server = socketserver.ThreadingTCPServer(('0.0.0.0',9999),MyHandler)
    print(server)  #<socketserver.ThreadingTCPServer object at 0x033CFA50>
    server.serve_forever()
    利用socketserver实现群聊
    
    import threading
    import socketserver
    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): #当服务端接收到新的请求后,baserequestHandler新类就会实例化 并一次执行setup ,try handle,finally finish
        clients = {}
        def setup(self):
            self.event = threading.Event()
            self.clients[self.client_address] = self.request
    
        def finish(self):
            self.clients.pop(self.client_address)
            self.event.set()
    
        def handle(self):#相当于socket的recv方法,每个不同的连接上请求过来后,生成连接的socket对象
    #就是self.request,客户端地址self.client.address
            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():
                    self.request.send(msg)
            print('END')
    addr = ('0.0.0.0',9999)
    server = socketserver.ThreadingTCPServer(addr,ChatHandler)  #baseserver源码serve_forever函数有try...finally关闭连接
    server_thread = threading.Thread(target=server.serve_forever,name='ChatServer',daemon=True).start()
    
    try:
        while True:
            cmd = input("please set a exit code >>>")
            if cmd.strip() == 'quit':
                break
    except Exception as e:
        print(e)
    except KeyboardInterrupt:
        sys.exit(0
    """
    通过打印可以看出,客户端主动断开连接,会导致revc方法立即返回一个空bytes,并没有同时抛出异常
    当循环回到recv这一句话会抛出异常,所以通过判断data数据是否为空来判断客户端是否断开
    
    """
    def handle(self):
        while not self.event.is_set():
            data = self.request.recv(1024)
            if not data or data =='quit':
                break
    
    """
    总结:
    为每一个连接提供RequestHandlerClass类实例,依次调用setup,handle,finish方法,并且使用
    try。。。finally结构保证finish方法一定被调用,这些方法一次执行完成,如果想维持这个连接和客户端通信
    就需要在handler中循环使用
    
    """
    本文为原创文章,转载请标明出处
  • 相关阅读:
    [原创]Android中LocationManager的简单使用,获取当前位置
    Android远程图片获取和本地缓存
    Android wakelock机制
    android上的缓存、缓存算法和缓存框架
    052 自动将每日的日志增量导入到hive中
    051 日志案例分析(PV,UV),以及动态分区
    050 sqoop的使用
    049 CDH商业版本的搭建(hadoop5.3.6 +hive+sqoop)
    000 Python的运行
    048 hive运行的相关配置
  • 原文地址:https://www.cnblogs.com/harden13/p/9196587.html
Copyright © 2011-2022 走看看