• socketserver多线程处理


    一、简介

      SocketServer简化了网络服务器的编写。在进行socket创建时,使用SocketServer会大大减少创建的步骤,并且SocketServer使用了select它有5个类:BaseServer,TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。后4个类是同步进行处理的,另外通过ForkingMixIn和ThreadingMixIn类来支持异步。

      SocketServer的5个类的继承关系

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

      

    二、提供的类型

       一是Server类:BaseServer/TCPServer/UDPServer用来接收客户的请求。TCPServer处理TCP请求,UDPServer处理UDP请求。BaserServer是基类,不能直接使用。TCPServer继承自BaseServer,UDPServer继承自TCPServer。

      二是Handler类:BaseRequestHandler/DatagramRequestHandler/StreamRequestHandler用来处理每一个客户请求。一般用使用BaseRequestHandler就行,但StreamRequestHandler/DatagramRequestHandler提供了一些特别的功能,前者用来处理流式(TCP)请求,后者处理数据报(UDP)请求。Server每收到一个客户请求就会创建一个Handler类示例来处理该请求。默认情况下,TCPServer/UDPServer是单进程单线程的模型,依次处理每个客户请求,一个请求处理完毕才能接着处理下一个请求。

      三是MixIn类:ForkingMixIn/ThreadingMixIn用来为Server提供多进程/多线程并发处理能力的。ForkingMixIn是多进程模型,ThreadingMixin是多线程模型。这里特别巧妙的是,你只要创建一个类,同时继承Server类和MixIn类就能自动获得并发处理请求的能力。该模块本身就直接提供了这种类。

    class ForkingUDPServer(ForkingMixIn, UDPServer): pass
    class ForkingTCPServer(ForkingMixIn, TCPServer): pass
    
    class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
    class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass三

     

     三、创建socketserver步骤

    • 必须先创建一个请求处理的类,并且这个类要继承BaseRequestHandle,并重写父类中的handle方法
    • 实例化一个server class,并且传递server ip 和刚创建的请求处理类给server class
    • 调用server class 对象的 handle_request() 或 server_forever()方法来开始处理请求
    • 关闭请求

      server.handle_request()   只处理一个请求

           server.forever()      处理多个请求,一直执行

    四、事例

      简单的接收客户端发送的信息,并将其转换成大写,再返回给客户端

      服务端: 

    # -*- coding: UTF-8 -*-
    import socketserver
    
    
    class MyTCPHandler(socketserver.BaseRequestHandler):
        """
        The request handler class for our server.
    
        It is instantiated once per connection to the server, and must
        override the handle() method to implement communication to the
        client.
        """
    
        def handle(self):
            while True:   # 多次接收客户端信息
                # self.request is the TCP socket connected to the client
                self.data = self.request.recv(1024).strip()
                print("{} wrote:".format(self.client_address[0]))
                print(self.data)
                # just send back the same data, but upper-cased
                self.request.sendall(self.data.upper())
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999
    
        # Create the server, binding to localhost on port 9999
        server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
    
        # Activate the server; this will keep running until you
        # interrupt the program with Ctrl-C
        server.serve_forever()
    

      客户端:

    # -*- coding: UTF-8 -*-
    
    import socket
    
    client = socket.socket()
    
    client.connect(('localhost', 9999))
    
    while True:
    
        msg = input('>>:').strip()
        if not msg:
            continue
        else:
            client.send(msg.encode('utf-8'))
            upData = client.recv(1024)
            print(upData.decode())

      

    五、多线程处理

      到目前为止我们所有的c/s连接都同时只能处理一个客户端请求,多个客户端请求时,要等前面的客户端请求关闭后才能执行,包括上面的代码也是。如果想让socketserver并发起来, 必须选择使用以下一个多并发的类:

    class socketserver.ForkingTCPServer
    
    class socketserver.ForkingUDPServer
    
    class socketserver.ThreadingTCPServer
    
    class socketserver.ThreadingUDPServer
    

      只需要改变一个地方就可以了

    server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
    

      服务端:

    import socketserver
    
    
    class MyTCPHandler(socketserver.BaseRequestHandler):
    
        def handle(self):
            while True:
                # self.request is the TCP socket connected to the client
                self.data = self.request.recv(1024).strip()
                print("{} wrote:".format(self.client_address[0]))
                print(self.data)
                # just send back the same data, but upper-cased
                self.request.sendall(self.data.upper())
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999
        server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
        server.serve_forever()
    

     

      

  • 相关阅读:
    软件测试(理论基础)
    Android NDK常见配置问题的解决方案
    Eclemma各种安装方式以及安装失败解决
    检测Buffer Overflow的几种方法
    转: 跟我一起写 Makefile
    流敏感、路径敏感、上下文敏感
    Symbolic Exectuion with Mixed ConcreteSymbolic Solving
    基于ajc的代码编织
    第一次个人编程作业
    第一次博客作业
  • 原文地址:https://www.cnblogs.com/bigberg/p/7763503.html
Copyright © 2020-2023  润新知