• SocketServer-实现并发处理


    Python提供了两个基本的socket模块。

    一个是socket,它提供了标准的BSD Socket API;另一个是socketServer,它提供了服务器中心类,可以简化网络服务器的开发,其实就是对socket()的再封装。

    1.前言:

    虽说用Python编写简单的网络程序很方便,但复杂一点的网络程序还是用现成的框架比较好。这样就可以专心事务逻辑,而不是套接字的各种细节。SocketServer模块简化了编写网络服务程序的任务。同时SocketServer模块也是Python标准库中很多服务器框架的基础。

    2.网络服务类:

    SocketServer提供了4个基本的服务类:

    TCPServer针对TCP套接字流

    UDPServer针对UDP数据报套接字

    UnixStreamServer和UnixDatagramServer针对UNIX域套接字,不常用。

    3.请求处理类:

    要实现一项服务,还必须派生一个handler class请求处理类,并重写父类的handle()方法。handle方法就是用来专门是处理请求的。该模块是通过服务类和请求处理类组合来处理请求的。

    SocketServer模块提供的请求处理类有BaseRequestHandler,以及它的派生类StreamRequestHandler和DatagramRequestHandler。从名字看出可以一个处理流式套接字,一个处理数据报套接字。

    4.总结用SocketServer创建一个服务的步骤:

    1). 创建一个request handler class(请求处理类),并且这个类要继承BaseRequestHandler class,而且还要重写父类里面的handle()方法,跟客户端所有的交互都是在handle()里面完成的。

    2). 实例化一个server class对象(TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer 四选一),并将服务的地址和之前创建的request handler class(请求处理类)传递给实例化后的server class对象。

    3). 调用server class对象的handle_request() (只处理一个请求)或 serve_forever()(处理多个请求)方法来开始处理请求。

    5.

    ----socketserver

      虽说用Python编写简单的网络程序很方便,但复杂一点的网络程序还是用现成的框架比较 好。这样就可以专心事务逻辑,而不是套接字的各种细节。SocketServer模块简化了编写网络服务程序的任务。同时SocketServer模块也 是Python标准库中很多服务器框架的基础。

    socketserver在python2中为SocketServer,在python3种取消了首字母大写,改名为socketserver。

    socketserver中包含了两种类,一种为服务类(server class),一种为请求处理类(request handle class)。前者提供了许多方法:像绑定,监听,运行…… (也就是建立连接的过程) 后者则专注于如何处理用户所发送的数据(也就是事务逻辑)。

      一般情况下,所有的服务,都是先建立连接,也就是建立一个服务类的实例,然后开始处理用户请求,也就是建立一个请求处理类的实例。

    一个基于SocketServer的服务器示例:
    
    
    from SocketServer import TCPServer,StreamRequestHandler
    
    #定义请求处理类
    
    class Handler(StreamRequestHandler):
    
    def handle(self):
    
    addr = self.request.getpeername()
    
    print 'Got connection from ',addr
    
    self.wfile.write('Thank you for connecting')
    
    server = TCPServer(('',1234), handler)#实例化服务类对象
    
    server.server_forever()#开启服务 
    

    5.实现异步,支持多连接

    前面介绍服务类时提到过,四个基本的服务类默认是同步模型的。要想支持异步可以利用多继承从ForkingMixIn 或ThreadingMixInmix-in classes和一个基本的服务类继承来定义一个支持异步的服务类。比如:

    class Server(ThreadingMixIn, TCPServer): pass

    ForkingMixIn 要考虑进程间的通信。ThreadingMixIn要考虑线程访问同一变量时的同步和互斥。

    一个使用了多线程处理的服务器示例:

    from SocketServer import TCPServer, ThreadingMixIn, StreamRequestHandler 
    #定义支持多线程的服务类,注意是多继承 
    class Server(ThreadingMixIn, TCPServer): pass
    #定义请求处理类 
    class Handler(StreamRequestHandler): 
    def handle(self): 
    addr = self.request.getpeername() 
    print 'Got connection from ',addr 
    self.wfile.write('Thank you for connection') 
    server = Server(('', 1234), Handler)#实例化服务类 
    server.serve_forever()#开启服务
    

    SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进 程” 专门负责处理当前客户端的所有请求。

    注:导入模块的时候 3.x版本是socketserver 2.x版本是SocketServer

      启动服务端程序

    • 执行 TCPServer.init 方法,创建服务端Socket对象并绑定 IP 和 端口
    • 执行 BaseServer.init 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 - MyRequestHandle赋值给 self.RequestHandlerClass
    • 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ... 当客户端连接到达服务器
    • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
    • 执行 ThreadingMixIn.process_request_thread 方法
    • 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行  自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用  MyRequestHandler的handle方法)

    1. SocketServer基础-服务器端:

    import socketserver
    
    class MyTCPHandler(socketserver.BaseRequestHandler): #自己写的请求处理类,每个客户端的请求过来,都会实例它。MyTCPHandler
    
        def handle(self): #重写handle()
            while True:
                self.data = self.request.recv(1024).strip()
                print("{} wrote:".format(self.client_address[0])) #打印客户端的IP地址
                print(self.data)
                if not self.data: #客户端断开了
                    print(self.client_address,'has disconnected')
                    break
                self.request.sendall(self.data.upper()) #变成大写,传回给客户端。
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999
        server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
        server.serve_forever()
    

     SocketServer基础-客户端:

    import socket
    client=socket.socket()
    client.connect(('localhost',9999))
    while True:
        msg=input(">>:").strip()
        if len(msg)==0:continue
        client.send(msg.encode('utf-8'))
        data=client.recv(1024)
        print("recv:",data.decode())
    client.close()
    

     客户端运行结果:

    >>:ls
    recv: LS
    >>:df
    recv: DF
    >>:cmd
    recv: CMD
    >>:abc
    recv: ABC
    >>:
    

     2. SocketServer基础-服务器端:当客户端断开的时候抓住异常

    import socketserver
    
    class MyTCPHandler(socketserver.BaseRequestHandler): #自己写的请求处理类,每个客户端的请求过来,都会实例它。MyTCPHandler
    
        def handle(self): #重写handle()
            while True:
                try:
                    self.data = self.request.recv(1024).strip()
                    print("{} wrote:".format(self.client_address[0])) #打印客户端的IP地址
                    print(self.data)
    
                    self.request.sendall(self.data.upper()) #变成大写,传回给客户端。
                except ConnectionResetError as e:
                    print('Error is: ',e) #客户端断开时抛出的异常
                    break
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999
        server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
        server.serve_forever()
    

     SocketServer基础-客户端:当客户端断开的时候抓住异常

    import socket
    client=socket.socket()
    client.connect(('localhost',9999))
    while True:
        msg=input(">>:").strip()
        if len(msg)==0:continue
        client.send(msg.encode('utf-8'))
        data=client.recv(1024)
        print("recv:",data.decode())
    client.close()
    

    客户端运行结果:

    >>:ls
    recv: LS
    >>:df
    recv: DF
    >>:abc
    recv: ABC
    >>:
    Process finished with exit code 1
    

     服务器端运行结果:

    127.0.0.1 wrote:
    b'ls'
    127.0.0.1 wrote:
    b'df'
    127.0.0.1 wrote:
    b'abc'
    error is:  [WinError 10054] An existing connection was forcibly closed by the remote host
    

     3. 实现多并发-服务器端:

    import socketserver
    
    class MyTCPHandler(socketserver.BaseRequestHandler): #自己写的请求处理类,每个客户端的请求过来,都会实例它。MyTCPHandler
    
        def handle(self): #重写handle()
            while True:
                try:
                    self.data = self.request.recv(1024).strip()
                    print("{} wrote:".format(self.client_address[0])) #打印客户端的IP地址
                    print(self.data)
    
                    self.request.sendall(self.data.upper()) #变成大写,传回给客户端。
                except ConnectionResetError as e:
                    print('Error is: ',e) #客户端断开时抛出的异常
                    break
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999
        server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
        server.serve_forever()
    

     实现多并发-客户端:

    import socket
    client=socket.socket()
    client.connect(('localhost',9999))
    while True:
        msg=input(">>:").strip()
        if len(msg)==0:continue
        client.send(msg.encode('utf-8'))
        data=client.recv(1024)
        print("recv:",data.decode())
    client.close()
    

    多个客户端同时连服务器,互相没有影响

     
  • 相关阅读:
    HDU4372 Count the Buildings
    Luogu4292 WC2010重建计划
    「学习笔记」二项式反演
    微软Power BI 每月功能更新系列——10月Power BI 新功能学习
    用Synoptic Panel自定义基于图形的可视化控件--制作一张剧场售票统计报表
    Power BI十大视觉效果,知多少?
    微软Power BI 每月功能更新系列——3月Power BI 新功能学习
    微软Power BI 每月功能更新系列——4月Power BI 新功能学习
    如何使用DAX函数解决动态图表标题
    如何用DAX实现查看每个月中不同类别排名前一位,以及一个简单的svg案例
  • 原文地址:https://www.cnblogs.com/momo8238/p/7306535.html
Copyright © 2020-2023  润新知