zoukankan      html  css  js  c++  java
  • Python3中的SocketServer

      socket并不能多并发,只能支持一个用户,socketserver 简化了编写网络服务程序的任务,socketserver是socket的在封装。socketserver在python2中为SocketServer,在python3种取消了首字母大写,改名为socketserver。socketserver中包含了两种类,一种为服务类(server class),一种为请求处理类(request handle class)。前者提供了许多方法:像绑定,监听,运行…… (也就是建立连接的过程) 后者则专注于如何处理用户所发送的数据(也就是事务逻辑)。一般情况下,所有的服务,都是先建立连接,也就是建立一个服务类的实例,然后开始处理用户请求,也就是建立一个请求处理类的实例。
     
    socketserver一共有这么几种类型:
     
    1. class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
    2. class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
    3. class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
    4. class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)
     
    继承关系图:
    +------------+
    | BaseServer | 
    +------------+
          |
          v
    +-----------+        +------------------+
    | TCPServer |------->| UnixStreamServer |
    +-----------+        +------------------+
          |
          v
    +-----------+        +--------------------+
    | UDPServer |------->| UnixDatagramServer |
    +-----------+        +--------------------+
     
    如何创建一个socketserver :
     
    1. First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests.   
    2. Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.
    3. Then call the handle_request() orserve_forever() method of the server object to process one or many requests.
    4. Finally, call server_close() to close the socket.
     
      1. 创建一个请求处理的类,并且这个类要继承 BaseRequestHandlerclass ,并且还要重写父类里handle()方法;
      2. 你必须实例化 TCPServer,并且传递server IP和你上面创建的请求处理类,给这个TCPServer;
      3. server.handle_requese()#只处理一个请求,server.server_forever()处理多个一个请求,永远执行
      4. 关闭连接server_close()
     
    socketserver例子:
     
     
    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):  #请求处理类,所有请求的交互都是在handle里执行的
            # self.request is the TCP socket connected to the client
            self.data = self.request.recv(1024).strip()#每一个请求都会实例化MyTCPHandler(socketserver.BaseRequestHandler):
            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())#sendall是重复调用send.
    
    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()
     
     server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)   #线程
    # server  = socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler) #多进程 linux适用
    # server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) 单进程
    
     
    socketserver.py源码解读(多线程如何开启后续补充)
     
    def process_request(self, request, client_address):
        """Start a new thread to process the request."""
        t = threading.Thread(target = self.process_request_thread,    #开始一个新线程传一个实例进去
                             args = (request, client_address))
        t.daemon = self.daemon_threads
        t.start()
     
    class socketserver.BaseServer(server_address, RequestHandlerClass) 主要有以下方法: 
     
    class socketserver.BaseServer(server_address, RequestHandlerClass)
    This is the superclass of all Server objects in the module. It defines the interface, given below, but does not implement most of the methods, which is done in subclasses. The two parameters are stored in the respective server_address and RequestHandlerClass attributes.
     
    fileno()  #返回文件描述符
    Return an integer file descriptor for the socket on which the server is listening. This function is most commonly passed to selectors, to allow monitoring multiple servers in the same process.
     
    handle_request() #处理单个请求
    Process a single request. This function calls the following methods in order: get_request(), verify_request(), and process_request(). If the user-provided handle() method of the handler class raises an exception, the server’s handle_error() method will be called. If no request is received within timeout seconds, handle_timeout() will be called and handle_request() will return.
     
    serve_forever(poll_interval=0.5)  #每0.5秒检查下是否发了shutdown信号,做一些清理工作
    Handle requests until an explicit(明确的) shutdown() request. Poll(检查) for shutdown every poll_interval seconds. Ignores the timeout attribute. It also calls service_actions(), which may be used by a subclass or mixin to provide actions specific to a given service. For example, the ForkingMixIn class uses service_actions() to clean up zombie child processes.

    Changed in version 3.3: Added service_actions call to the serve_forever method.
     
    service_actions() #python3.3里加入,
    This is called in the serve_forever() loop. This method can be overridden by subclasses or mixin classes to perform actions specific to a given service, such as cleanup actions.

    New in version 3.3.

    shutdown() #停掉
    Tell the serve_forever() loop to stop and wait until it does.

    server_close()#关闭
    Clean up the server. May be overridden.
     
    address_family #地址蔟
    The family of protocols to which the server’s socket belongs. Common examples are socket.AF_INET and socket.AF_UNIX.
     
    RequestHandlerClass #请求处理类
    The user-provided request handler class; an instance of this class is created for each request.

    server_address#IP地址
    The address on which the server is listening. The format of addresses varies depending on the protocol family; see the documentation for the socket module for details. For Internet protocols, this is a tuple containing a string giving the address, and an integer port number: ('127.0.0.1', 80), for example.

    socket #
    The socket object on which the server will listen for incoming requests.

    The server classes support the following class variables:
     
    allow_reuse_address  #准许重用地址,普通的socket重用地址
    Whether the server will allow the reuse of an address. This defaults to False, and can be set in subclasses to change the policy.
     
    request_queue_size  #
    The size of the request queue. If it takes a long time to process a single request, any requests that arrive while the server is busy are placed into a queue, up to request_queue_size requests. Once the queue is full, further requests from clients will get a “Connection denied” error. The default value is usually 5, but this can be overridden by subclasses.

    socket_type  #协议类型
    The type of socket used by the server; socket.SOCK_STREAM and socket.SOCK_DGRAM are two common values.
     
    timeout #超时
    Timeout duration, measured in seconds, or None if no timeout is desired. If handle_request() receives no incoming requests within the timeout period, the handle_timeout() method is called.

    There are various server methods that can be overridden by subclasses of base server classes like TCPServer; these methods aren’t useful to external users of the server object.
     
    finish_request()  
    Actually processes the request by instantiating RequestHandlerClass and calling its handle() method.
     
     
    get_request()  #
    Must accept a request from the socket, and return a 2-tuple containing the new socket object to be used to communicate with the client, and the client’s address.

    handle_error(request, client_address) #处理错误
    This function is called if the handle() method of a RequestHandlerClass instance raises an exception. The default action is to print the traceback to standard output and continue handling further requests.

    handle_timeout() #
    This function is called when the timeout attribute has been set to a value other than None and the timeout period has passed with no requests being received. The default action for forking servers is to collect the status of any child processes that have exited, while in threading servers this method does nothing.
     
    process_request(request, client_address) #单个请求
    Calls finish_request() to create an instance of the RequestHandlerClass. If desired, this function can create a new process or thread to handle the request; the ForkingMixIn and ThreadingMixIn classes do this.

    server_activate()
    Called by the server’s constructor to activate the server. The default behavior for a TCP server just invokes listen() on the server’s socket. May be overridden.

    server_bind() #内部调用
    Called by the server’s constructor to bind the socket to the desired address. May be overridden.

    verify_request(request, client_address) #判断一个请求是否合法
    Must return a Boolean value; if the value is True, the request will be processed, and if it’s False, the request will be denied. This function can be overridden to implement access controls for a server. The default implementation always returns True.
     
    服务端和客户端代码演示:
     
    Server : 
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    # Author: Colin Yao
    
    import socketserver
    
    class MyTCPHandler(socketserver.BaseRequestHandler):
    
        def handle(self):  #所有请求的交互都是在handle里执行的,
            while True:
                try:
                    self.data = self.request.recv(1024).strip()#每一个请求都会实例化MyTCPHandler(socketserver.BaseRequestHandler):
                    print("{} wrote:".format(self.client_address[0]))
                    print(self.data)
                    self.request.sendall(self.data.upper())#sendall是重复调用send.
                except ConnectionResetError as e:
                    print("err ",e)
                    break
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999 #windows
        #HOST, PORT = "0.0.0.0", 9999 #Linux
        server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)   #线程
        server.serve_forever() 
    Client : 
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    # Author: Colin Yao
    #客户端
    import socket
    client = socket.socket() #定义协议类型,相当于生命socket类型,同时生成socket连接对象
    client.connect(('192.168.84.130',9999))
    while True:
        msg = input(">>>").strip()
        if len(msg) ==0:continue
        client.send(msg.encode("utf-8"))
        data = client.recv(1024)#这里是字节1k
        print("recv:>",data.decode())
    client.close()
  • 相关阅读:
    [学习总结]1、View的scrollTo 和 scrollBy 方法使用说明和区别
    [项目总结]Android 手动显示和隐藏软键盘
    Ubuntu系统下C语言编程
    windows API程序设计(一个简单的窗口)
    小程序的四种文件类型和基本结构
    小乌龟使用错误
    ROS通信编程与仿真工具
    小程序的事件机制--捕捉与回调,catch与bind
    Sql 中Collate用法
    tf.data.dataset
  • 原文地址:https://www.cnblogs.com/sean-yao/p/7836400.html
Copyright © 2011-2022 走看看