• 基于socketserver实现并发的socket编程


    基于socketserver实现并发的socket编程

    一、基于TCP协议

    基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环

    socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题)

    1.1server类

    [126-基于socketserver实现并发的socket-server类.png?x-oss-process=style/watermark

    1.2 request类

    [126-基于socketserver实现并发的socket-request类.png?x-oss-process=style/watermark

    1.3 继承关系

    [126-基于socketserver实现并发的socket-继承关系1.png?x-oss-process=style/watermark

    [126-基于socketserver实现并发的socket-继承关系2.png?x-oss-process=style/watermark

    [126-基于socketserver实现并发的socket-继承关系3.png?x-oss-process=style/watermark

    1.4 服务端

    # 使用socketserver写服务端
    # 导入模块
    import socketserver
    
    # 自己定义一个类, 必须继承BaseRequestHandler
    class Mytcp(socketserver.BaseRequestHandler):
        # 必须要重写handle方法
        def handle(self):
            while True:  # 通信循坏
                print(self)
    
                # 给客户端回消息
                print(self.request)
                print(self.client_address)
                # 接收数据,  conn对象就是request
                data = self.request.recv(1024)
                print(data)
                if len(data) == 0:
                    return
                # 发送数据
                self.request.send(b'234')
    
    
    if __name__ == '__main__':
        # 实例化得到一个tcp连接对象, Threading意思是说,只要来了请求,他就自动开线程来处理连接跟交互数据
        # 第一个参数是绑定的地址, 第二个参数传一个类
        server = socketserver.ThreadingTCPServer(('127.0.0.1',8009), Mytcp)
    
        # 一直监听
        # 可以这么理解:只要来一个请求, 就起一个线程(连接一个人, 做交互)
        server.serve_forever()
    
    

    1.5 客户端

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8080))  # 指定服务端ip和端口
    
    while True:
        # msg=input('>>: ').strip() #msg=''
        msg = 'client33333'  # msg=''
        if len(msg) == 0: continue
        phone.send(msg.encode('utf-8'))
        data = phone.recv(1024)
        print(data)
    
    phone.close()
    

    1.6 客户端2

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8080))  # 指定服务端ip和端口
    
    while True:
        # msg=input('>>: ').strip() #msg=''
        msg = 'client11111'  # msg=''
        if len(msg) == 0: continue
        phone.send(msg.encode('utf-8'))
        data = phone.recv(1024)
        print(data)
    
    phone.close()
    

    二、基于UDP协议

    2.1 服务器

    import socketserver
    
    class MyUdp(socketserver.BaseRequestHandler):
        def handle(self):
    
            # print(self.request)
            # data=self.request[0]
            # print(data)
            data, addr  = self.request[1].recvfrom(1024)
            print(data)
            self.request[1].sendto('xxxx'.encode('utf-8'),addr)
            # self.request[1].sendto('xxxx'.encode('utf-8'),self.client_address)
    
    
    
            # while True:
            #     try:
            #         data = self.request.recvfrom(1024)
            #         print(data)
            #         # self.request.sendto(b'123')
            #
            #     except Exception as e:
            #         print(e)
            #         break
    
    if __name__ == '__main__':
        server = socketserver.ThreadingUDPServer(('127.0.0.1', 8010), MyUdp)
        server.serve_forever()
    

    2.2 客户端1

    
    import socket
    
    client=socket.socket(type=socket.SOCK_DGRAM)
    
    client.sendto('randy'.encode('utf-8'),('127.0.0.1', 8010))
    data = client.recvfrom(1024)
    print(data)
    

    2.3 客户端2

    import socket
    
    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 数据报协议-》udp
    
    while True:
        # msg=input('>>: ').strip() #msg=''
        msg = 'client2222'
        client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
        data, server_addr = client.recvfrom(1024)
        print(data)
    
    client.close()
    

    三、socketserver源码分析

    ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1', 8080),FtpServer)
    ftpserver.serve_forever()
    
     '''
            1 ThreadingTCPServer实例化:走__init__方法
                -ThreadingTCPServer(ThreadingMixIn, TCPServer)的__init__方法,没有,走的父类:TCPServer(BaseServer)的__init__
                -TCPServer(BaseServer)的__init__又调用了父类的__init__
                    -赋值操作:self.server_address = server_address
                              self.RequestHandlerClass = RequestHandlerClass
                    -数据放到谁当中了?放到了server这个对象中
                -socket.bind()
                -socker.listen()
            2  server.serve_forever()   
                -一堆代码不需要要管:self._handle_request_noblock
                    -request, client_address = self.get_request()
                        -self.get_request()在Tcpserver这个类: self.socket.accept()
                    - self.process_request(request, client_address):ThreadingMixIn类的process_request
                        -开启线程执行ThreadingMixIn类的process_request_thread,执行了finish_request(request, client_address, self) 在 BaseServer 类中
                            -request :就是咱的连接对象,conn
                            -client_address 客户端ip和端口
                            -self:server对象,实例化得到的server对象
                            -实例化RequestHandlerClass(自己创建的类)得到一个对象:会走__init__方法
                            -RequestHandlerClass自己创建的类没有init方法,走的BaseRequestHandler类的__init__
                            -会执行handle方法,通信逻辑
        '''
    

    查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer

    1. 实例化得到ftpserver,先找类ThreadingTCPServer的__init__,在TCPServer中找到,进而执行server_bind,serve6666666666666666665555555555555r_active
    2. 找ftpserver下的serve_forever,在BaseServer中找 到,进而执行self._handle_request_noblock(),该方法同样是在BaseServer中
    3. 执行self._handle_request_noblock()进而执行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),然后执行self.process_request(request, client_address)
    4. 在ThreadingMixIn中找到process_request,开启多线程应对并发,进而执行process_request_thread,执行self.finish_request(request, client_address)
    5. 上述四部分完成了链接循环,本部分开始进入处理通讯部分,在BaseServer中找到finish_request,触发我们自己定6556
    6. 656565555555555555555义的类的实例化,去找__init__方法,而我们自己定义的类没有该方法,则去它的父类也就是BaseRequestHandler中找....

    3.1 源码分析总结

    基于tcp的socketserver我们自己定义的类中的

    • self.server即套接字对象

    • self.request即一个链接

    • self.client_address即客户端地址

    基于udp的socketserver我们自己定义的类中的

    • self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)

    • self.client_address即客户端地址

    在当下的阶段,必将由程序员来主导,甚至比以往更甚。
  • 相关阅读:
    gRPC详解
    vue 实现无限向上滚动
    vue 封装highcharts组件
    《数据结构与算法之美》32——分治算法
    《数据结构与算法之美》31——贪心算法
    《数据结构与算法之美》30——回溯算法
    《数据结构与算法之美》29——动态规划实战
    《数据结构与算法之美》28——动态规划理论
    《数据结构与算法之美》27——初识动态规划
    《数据结构与算法之美》26——广度优先搜索与深度优先搜索
  • 原文地址:https://www.cnblogs.com/randysun/p/11517086.html
Copyright © 2020-2023  润新知