zoukankan      html  css  js  c++  java
  • socketserver模块

    一、socketserver模块说明

    • socket并不能多并发,只能支持一个用户,socketserver 简化了编写网络服务程序的任务,socketserver是socket的在封装。socketserver在python2中为SocketServer,在python3种取消了首字母大写,改名为socketserver。
    • socketserver内部使用IO多路复用以及“多线程”和“多进程”,从而实现并发处理多个客户端请求的scoket服务端。即,每个客户端请求连接到服务器时,socket服务端都会在服务器是创建一个“线程”或“进程”专门负责处理当前客户端的所有请求。
    • socketserver中包含了两种类,一种为服务类(server class),一种为请求处理类(request handle class)。前者提供了许多方法:像绑定,监听,运行…… (也就是建立连接的过程);后者则专注于如何处理用户所发送的数据(也就是事务逻辑)。一般情况下,所有的服务,都是先建立连接,也就是建立一个服务类的实例,然后开始处理用户请求,也就是建立一个请求处理类的实例。

    二、server类型介绍

      1.5种server类 BaseServer,TCPServer,UnixStreamServer,UDPServer,UnixDatagramServer。 注意:BaseServer不直接对外服务。

    • class socketserver.BaseServer:这是模块中的所有服务器对象的超类。包含服务器的核心功能与混合类(min-in)的钩子功能.这个类主用于派生,不要直接生成这个类的类对象,它定义了接口,但是大多数的方法不实现,在子类中进行细化。
    • class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)  支持使用IPV4的TCP协议的服务器,address是一个(host,port)元组.Handler是BaseRequestHandler或StreamRequestHandler类的子类的实例.
    • class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)  支持使用IPV4的UDP协议的服务器,address和handler与TCPServer类似.
    • class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)  使用UNIX域套接字实现面向数据流协议的服务器,继承自TCPServer.
    • class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)  使用UNIX域套接字实现数据报协议的服务器,继承自UDPServer.

      2.继承关系

      3.BaseServer方法

     1 BaseServer.fileno():返回服务器监听套接字的整数文件描述符。通常用来传递给select.select(), 以允许一个进程监视多个服务器。
     2 
     3 BaseServer.handle_request():处理单个请求。处理顺序:get_request(), verify_request(), process_request()。如果用户提供handle()方法抛出异常,将调用服务器的handle_error()方法。如果self.timeout内没有请求收到, 将调用handle_timeout()并返回handle_request()。
     4 
     5 BaseServer.serve_forever(poll_interval=0.5): 处理请求,直到一个明确的shutdown()请求。每poll_interval秒轮询一次shutdown。忽略self.timeout。如果你需要做周期性的任务,建议放置在其他线程。
     6 
     7 BaseServer.shutdown():告诉serve_forever()循环停止并等待其停止。python2.6版本。
     8 
     9 BaseServer.address_family: 地址家族,比如socket.AF_INET和socket.AF_UNIX。
    10 
    11 BaseServer.RequestHandlerClass:用户提供的请求处理类,这个类为每个请求创建实例。
    12 
    13 BaseServer.server_address:服务器侦听的地址。格式根据协议家族地址的各不相同,请参阅socket模块的文档。
    14 
    15 BaseServer.socketSocket:服务器上侦听传入的请求socket对象的服务器。
    16 
    17 服务器类支持下面的类变量:
    18 
    19 BaseServer.allow_reuse_address:服务器是否允许地址的重用。默认为false ,并且可在子类中更改。
    20 
    21 BaseServer.request_queue_size
    22 
    23 请求队列的大小。如果单个请求需要很长的时间来处理,服务器忙时请求被放置到队列中,最多可以放request_queue_size个。一旦队列已满,来自客户端的请求将得到 “Connection denied”错误。默认值通常为5 ,但可以被子类覆盖。
    24 
    25 BaseServer.socket_type:服务器使用的套接字类型; socket.SOCK_STREAM和socket.SOCK_DGRAM等。
    26 
    27 BaseServer.timeout:超时时间,以秒为单位,或 None表示没有超时。如果handle_request()在timeout内没有收到请求,将调用handle_timeout()。
    28 
    29 下面方法可以被子类重载,它们对服务器对象的外部用户没有影响。
    30 
    31 BaseServer.finish_request():实际处理RequestHandlerClass发起的请求并调用其handle()方法。 常用。
    32 
    33 BaseServer.get_request():接受socket请求,并返回二元组包含要用于与客户端通信的新socket对象,以及客户端的地址。
    34 
    35 BaseServer.handle_error(request, client_address):如果RequestHandlerClass的handle()方法抛出异常时调用。默认操作是打印traceback到标准输出,并继续处理其他请求。
    36 
    37 BaseServer.handle_timeout():超时处理。默认对于forking服务器是收集退出的子进程状态,threading服务器则什么都不做。
    38 
    39 BaseServer.process_request(request, client_address) :调用finish_request()创建RequestHandlerClass的实例。如果需要,此功能可以创建新的进程或线程来处理请求,ForkingMixIn和ThreadingMixIn类做到这点。常用。
    40 
    41 BaseServer.server_activate():通过服务器的构造函数来激活服务器。默认的行为只是监听服务器套接字。可重载。
    42 
    43 BaseServer.server_bind():通过服务器的构造函数中调用绑定socket到所需的地址。可重载。
    44 
    45 BaseServer.verify_request(request, client_address):返回一个布尔值,如果该值为True ,则该请求将被处理,反之请求将被拒绝。此功能可以重写来实现对服务器的访问控制。默认的实现始终返回True。client_address可以限定客户端,比如只处理指定ip区间的请求。 常用。
    BaseServer方法
      1 class BaseServer:
      2 
      3     """Base class for server classes.
      4 
      5     Methods for the caller:
      6 
      7     - __init__(server_address, RequestHandlerClass)
      8     - serve_forever(poll_interval=0.5)
      9     - shutdown()
     10     - handle_request()  # if you do not use serve_forever()
     11     - fileno() -> int   # for selector
     12 
     13     Methods that may be overridden:
     14 
     15     - server_bind()
     16     - server_activate()
     17     - get_request() -> request, client_address
     18     - handle_timeout()
     19     - verify_request(request, client_address)
     20     - server_close()
     21     - process_request(request, client_address)
     22     - shutdown_request(request)
     23     - close_request(request)
     24     - service_actions()
     25     - handle_error()
     26 
     27     Methods for derived classes:
     28 
     29     - finish_request(request, client_address)
     30 
     31     Class variables that may be overridden by derived classes or
     32     instances:
     33 
     34     - timeout
     35     - address_family
     36     - socket_type
     37     - allow_reuse_address
     38 
     39     Instance variables:
     40 
     41     - RequestHandlerClass
     42     - socket
     43 
     44     """
     45 
     46     timeout = None
     47 
     48     def __init__(self, server_address, RequestHandlerClass):
     49         """Constructor.  May be extended, do not override."""
     50         self.server_address = server_address
     51         self.RequestHandlerClass = RequestHandlerClass
     52         self.__is_shut_down = threading.Event()
     53         self.__shutdown_request = False
     54 
     55     def server_activate(self):
     56         """Called by constructor to activate the server.
     57 
     58         May be overridden.
     59 
     60         """
     61         pass
     62 
     63     def serve_forever(self, poll_interval=0.5):
     64         """Handle one request at a time until shutdown.
     65 
     66         Polls for shutdown every poll_interval seconds. Ignores
     67         self.timeout. If you need to do periodic tasks, do them in
     68         another thread.
     69         """
     70         self.__is_shut_down.clear()
     71         try:
     72             # XXX: Consider using another file descriptor or connecting to the
     73             # socket to wake this up instead of polling. Polling reduces our
     74             # responsiveness to a shutdown request and wastes cpu at all other
     75             # times.
     76             with _ServerSelector() as selector:
     77                 selector.register(self, selectors.EVENT_READ)
     78 
     79                 while not self.__shutdown_request:
     80                     ready = selector.select(poll_interval)
     81                     if ready:
     82                         self._handle_request_noblock()
     83 
     84                     self.service_actions()
     85         finally:
     86             self.__shutdown_request = False
     87             self.__is_shut_down.set()
     88 
     89     def shutdown(self):
     90         """Stops the serve_forever loop.
     91 
     92         Blocks until the loop has finished. This must be called while
     93         serve_forever() is running in another thread, or it will
     94         deadlock.
     95         """
     96         self.__shutdown_request = True
     97         self.__is_shut_down.wait()
     98 
     99     def service_actions(self):
    100         """Called by the serve_forever() loop.
    101 
    102         May be overridden by a subclass / Mixin to implement any code that
    103         needs to be run during the loop.
    104         """
    105         pass
    106 
    107     # The distinction between handling, getting, processing and finishing a
    108     # request is fairly arbitrary.  Remember:
    109     #
    110     # - handle_request() is the top-level call.  It calls selector.select(),
    111     #   get_request(), verify_request() and process_request()
    112     # - get_request() is different for stream or datagram sockets
    113     # - process_request() is the place that may fork a new process or create a
    114     #   new thread to finish the request
    115     # - finish_request() instantiates the request handler class; this
    116     #   constructor will handle the request all by itself
    117 
    118     def handle_request(self):
    119         """Handle one request, possibly blocking.
    120 
    121         Respects self.timeout.
    122         """
    123         # Support people who used socket.settimeout() to escape
    124         # handle_request before self.timeout was available.
    125         timeout = self.socket.gettimeout()
    126         if timeout is None:
    127             timeout = self.timeout
    128         elif self.timeout is not None:
    129             timeout = min(timeout, self.timeout)
    130         if timeout is not None:
    131             deadline = time() + timeout
    132 
    133         # Wait until a request arrives or the timeout expires - the loop is
    134         # necessary to accommodate early wakeups due to EINTR.
    135         with _ServerSelector() as selector:
    136             selector.register(self, selectors.EVENT_READ)
    137 
    138             while True:
    139                 ready = selector.select(timeout)
    140                 if ready:
    141                     return self._handle_request_noblock()
    142                 else:
    143                     if timeout is not None:
    144                         timeout = deadline - time()
    145                         if timeout < 0:
    146                             return self.handle_timeout()
    147 
    148     def _handle_request_noblock(self):
    149         """Handle one request, without blocking.
    150 
    151         I assume that selector.select() has returned that the socket is
    152         readable before this function was called, so there should be no risk of
    153         blocking in get_request().
    154         """
    155         try:
    156             request, client_address = self.get_request()
    157         except OSError:
    158             return
    159         if self.verify_request(request, client_address):
    160             try:
    161                 self.process_request(request, client_address)
    162             except Exception:
    163                 self.handle_error(request, client_address)
    164                 self.shutdown_request(request)
    165             except:
    166                 self.shutdown_request(request)
    167                 raise
    168         else:
    169             self.shutdown_request(request)
    170 
    171     def handle_timeout(self):
    172         """Called if no new request arrives within self.timeout.
    173 
    174         Overridden by ForkingMixIn.
    175         """
    176         pass
    177 
    178     def verify_request(self, request, client_address):
    179         """Verify the request.  May be overridden.
    180 
    181         Return True if we should proceed with this request.
    182 
    183         """
    184         return True
    185 
    186     def process_request(self, request, client_address):
    187         """Call finish_request.
    188 
    189         Overridden by ForkingMixIn and ThreadingMixIn.
    190 
    191         """
    192         self.finish_request(request, client_address)
    193         self.shutdown_request(request)
    194 
    195     def server_close(self):
    196         """Called to clean-up the server.
    197 
    198         May be overridden.
    199 
    200         """
    201         pass
    202 
    203     def finish_request(self, request, client_address):
    204         """Finish one request by instantiating RequestHandlerClass."""
    205         self.RequestHandlerClass(request, client_address, self)
    206 
    207     def shutdown_request(self, request):
    208         """Called to shutdown and close an individual request."""
    209         self.close_request(request)
    210 
    211     def close_request(self, request):
    212         """Called to clean up an individual request."""
    213         pass
    214 
    215     def handle_error(self, request, client_address):
    216         """Handle an error gracefully.  May be overridden.
    217 
    218         The default is to print a traceback and continue.
    219 
    220         """
    221         print('-'*40, file=sys.stderr)
    222         print('Exception happened during processing of request from',
    223             client_address, file=sys.stderr)
    224         import traceback
    225         traceback.print_exc()
    226         print('-'*40, file=sys.stderr)
    227 
    228     def __enter__(self):
    229         return self
    230 
    231     def __exit__(self, *args):
    232         self.server_close()
    BaseServer源码

      4.TCPServer方法

    • server_bind
    • server_activate
    • server_close
    • fileno
    • get_request
    • shutdown_request
    • close_request
      1 class TCPServer(BaseServer):
      2 
      3     """Base class for various socket-based server classes.
      4 
      5     Defaults to synchronous IP stream (i.e., TCP).
      6 
      7     Methods for the caller:
      8 
      9     - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
     10     - serve_forever(poll_interval=0.5)
     11     - shutdown()
     12     - handle_request()  # if you don't use serve_forever()
     13     - fileno() -> int   # for selector
     14 
     15     Methods that may be overridden:
     16 
     17     - server_bind()
     18     - server_activate()
     19     - get_request() -> request, client_address
     20     - handle_timeout()
     21     - verify_request(request, client_address)
     22     - process_request(request, client_address)
     23     - shutdown_request(request)
     24     - close_request(request)
     25     - handle_error()
     26 
     27     Methods for derived classes:
     28 
     29     - finish_request(request, client_address)
     30 
     31     Class variables that may be overridden by derived classes or
     32     instances:
     33 
     34     - timeout
     35     - address_family
     36     - socket_type
     37     - request_queue_size (only for stream sockets)
     38     - allow_reuse_address
     39 
     40     Instance variables:
     41 
     42     - server_address
     43     - RequestHandlerClass
     44     - socket
     45 
     46     """
     47 
     48     address_family = socket.AF_INET
     49 
     50     socket_type = socket.SOCK_STREAM
     51 
     52     request_queue_size = 5
     53 
     54     allow_reuse_address = False
     55 
     56     def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
     57         """Constructor.  May be extended, do not override."""
     58         BaseServer.__init__(self, server_address, RequestHandlerClass)
     59         self.socket = socket.socket(self.address_family,
     60                                     self.socket_type)
     61         if bind_and_activate:
     62             try:
     63                 self.server_bind()
     64                 self.server_activate()
     65             except:
     66                 self.server_close()
     67                 raise
     68 
     69     def server_bind(self):
     70         """Called by constructor to bind the socket.
     71 
     72         May be overridden.
     73 
     74         """
     75         if self.allow_reuse_address:
     76             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     77         self.socket.bind(self.server_address)
     78         self.server_address = self.socket.getsockname()
     79 
     80     def server_activate(self):
     81         """Called by constructor to activate the server.
     82 
     83         May be overridden.
     84 
     85         """
     86         self.socket.listen(self.request_queue_size)
     87 
     88     def server_close(self):
     89         """Called to clean-up the server.
     90 
     91         May be overridden.
     92 
     93         """
     94         self.socket.close()
     95 
     96     def fileno(self):
     97         """Return socket file number.
     98 
     99         Interface required by selector.
    100 
    101         """
    102         return self.socket.fileno()
    103 
    104     def get_request(self):
    105         """Get the request and client address from the socket.
    106 
    107         May be overridden.
    108 
    109         """
    110         return self.socket.accept()
    111 
    112     def shutdown_request(self, request):
    113         """Called to shutdown and close an individual request."""
    114         try:
    115             #explicitly shutdown.  socket.close() merely releases
    116             #the socket and waits for GC to perform the actual close.
    117             request.shutdown(socket.SHUT_WR)
    118         except OSError:
    119             pass #some platforms may raise ENOTCONN here
    120         self.close_request(request)
    121 
    122     def close_request(self, request):
    123         """Called to clean up an individual request."""
    124         request.close()
    TCPServer源码

      5.UDPServer方法

    • get_request
    • server_activate
    • shutdown_request
    • close_request
     1 class UDPServer(TCPServer):
     2 
     3     """UDP server class."""
     4 
     5     allow_reuse_address = False
     6 
     7     socket_type = socket.SOCK_DGRAM
     8 
     9     max_packet_size = 8192
    10 
    11     def get_request(self):
    12         data, client_addr = self.socket.recvfrom(self.max_packet_size)
    13         return (data, self.socket), client_addr
    14 
    15     def server_activate(self):
    16         # No need to call listen() for UDP.
    17         pass
    18 
    19     def shutdown_request(self, request):
    20         # No need to shutdown anything.
    21         self.close_request(request)
    22 
    23     def close_request(self, request):
    24         # No need to close anything.
    25         pass
    UDPServer源码

    三、request类(request handle class)

      1.request类

    • class BaseRequestHandler
    • class StreamRequestHandler(BaseRequestHandler)
    • class DatagramRequestHandler(BaseRequestHandler)

      

      BaseRequestHandle类的实例化可以实现以下方法:

    • sock.handle()调用该方法执行实际的请求操作.调用函数可以不带任何参数,但是几个实例变量包含有用的值.sock.request包含请求,sock.client_address包含客户端的地址,sock.server包含调用处理程序的实例.对于TCP之类的数据流服务,sock.request属性是套接字对象.

    • 对于数据报服务,还是包含收到数据的字节字符串.
    • sock.setup()该方法在handle()之前调用.默认情况下,不执行任何操作.如果希望服务器实现更多连接设置(如建立SSL连接),则无需调用该方法.

    • sock.finish()调用本方法可以在执行完handle()之后执行清除操作.默认情况下,不执行任何操作.如果setup()和handle()方法都不生成异常,则无需调用该方法.

    • 如果知道应用程序只能操纵面向数据流的连接(如TCP),那么应从StreamRequestHandle继承,而不是BaseRequestHandler.StreaRequestHandler类设置了两个属性,sock.wfile是将数据写入客户端的类文件对象,sock.rfile是从客户端读取数据的类文件对象.
    • 如果编写针对数据包操作的处理程序并将响应持续返回给发送方,那么它应当从DategramRequestHandler继承.它提供的类接口与StreamREquestHandler相同.

      2.继承图

      

      3.源码

     1 class BaseRequestHandler:
     2 
     3     """Base class for request handler classes.
     4 
     5     This class is instantiated for each request to be handled.  The
     6     constructor sets the instance variables request, client_address
     7     and server, and then calls the handle() method.  To implement a
     8     specific service, all you need to do is to derive a class which
     9     defines a handle() method.
    10 
    11     The handle() method can find the request as self.request, the
    12     client address as self.client_address, and the server (in case it
    13     needs access to per-server information) as self.server.  Since a
    14     separate instance is created for each request, the handle() method
    15     can define other arbitrary instance variables.
    16 
    17     """
    18 
    19     def __init__(self, request, client_address, server):
    20         self.request = request
    21         self.client_address = client_address
    22         self.server = server
    23         self.setup()
    24         try:
    25             self.handle()
    26         finally:
    27             self.finish()
    28 
    29     def setup(self):
    30         pass
    31 
    32     def handle(self):
    33         pass
    34 
    35     def finish(self):
    36         pass
    37 
    38 
    39 # The following two classes make it possible to use the same service
    40 # class for stream or datagram servers.
    41 # Each class sets up these instance variables:
    42 # - rfile: a file object from which receives the request is read
    43 # - wfile: a file object to which the reply is written
    44 # When the handle() method returns, wfile is flushed properly
    BaseRequestHandler源码
     1 class StreamRequestHandler(BaseRequestHandler):
     2 
     3     """Define self.rfile and self.wfile for stream sockets."""
     4 
     5     # Default buffer sizes for rfile, wfile.
     6     # We default rfile to buffered because otherwise it could be
     7     # really slow for large data (a getc() call per byte); we make
     8     # wfile unbuffered because (a) often after a write() we want to
     9     # read and we need to flush the line; (b) big writes to unbuffered
    10     # files are typically optimized by stdio even when big reads
    11     # aren't.
    12     rbufsize = -1
    13     wbufsize = 0
    14 
    15     # A timeout to apply to the request socket, if not None.
    16     timeout = None
    17 
    18     # Disable nagle algorithm for this socket, if True.
    19     # Use only when wbufsize != 0, to avoid small packets.
    20     disable_nagle_algorithm = False
    21 
    22     def setup(self):
    23         self.connection = self.request
    24         if self.timeout is not None:
    25             self.connection.settimeout(self.timeout)
    26         if self.disable_nagle_algorithm:
    27             self.connection.setsockopt(socket.IPPROTO_TCP,
    28                                        socket.TCP_NODELAY, True)
    29         self.rfile = self.connection.makefile('rb', self.rbufsize)
    30         if self.wbufsize == 0:
    31             self.wfile = _SocketWriter(self.connection)
    32         else:
    33             self.wfile = self.connection.makefile('wb', self.wbufsize)
    34 
    35     def finish(self):
    36         if not self.wfile.closed:
    37             try:
    38                 self.wfile.flush()
    39             except socket.error:
    40                 # A final socket error may have occurred here, such as
    41                 # the local error ECONNABORTED.
    42                 pass
    43         self.wfile.close()
    44         self.rfile.close()
    StreamRequestHandler源码
     1 class DatagramRequestHandler(BaseRequestHandler):
     2 
     3     """Define self.rfile and self.wfile for datagram sockets."""
     4 
     5     def setup(self):
     6         from io import BytesIO
     7         self.packet, self.socket = self.request
     8         self.rfile = BytesIO(self.packet)
     9         self.wfile = BytesIO()
    10 
    11     def finish(self):
    12         self.socket.sendto(self.wfile.getvalue(), self.client_address)
    DatagramRequestHandler源码

    四、线程与进程类

    • ForkingMinIn  实现了核心的进程化功能,用于与服务器类进行混合(min-in),以提供一些异步特性.不要直接生成这个类的对象
    • ThreadingMinIn  实现了核心的线程化功能,用于与服务器类进行混合(min-in),以提供一些异步特性,不要直接生成这个类的对象
    • ForkingTCPServer  ForkingMinIn与TCPServer的组合
    • ForkingUDPServer  ForkingMinIn与UDPServer的组合

    五、server类和request类关系与继承

     说明:

    六、TCPServer 实例

      1.创建一个server需要的几个步骤:

      原文:

    • First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests. 
    • Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.
    • Then call the handle_request() or serve_forever() method of the server object to process one or many requests.
    • Finally, call server_close() to close the socket.

      

      翻译:

    • 首先,您必须创建一个请求处理类的子类 继承BaseRequestHandlerclass,并重写父类里的handle()方法,该方法将处理传入的请求。
    • 其次,你必须实例化一个服务器的类,并且传递服务器的地址,端口和上面一步创建的类名。
    • 然后调用handle_request()或者serve_forever()方法来处理一个或多个请求。handle_request()只处理一个请求,serve_forever()处理多个请求,永远执行。
    • 最后,调用server_close()关闭套接字。

      

      2.实例1

      

    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) 单进程
    

      

      3.实例2

      Server端:

    import socketserver
    
    class Myserver(socketserver.BaseRequestHandler):
        def handle(self):  #self.request 就相当于一个 conn
            print(self.request.recv(1024).decode('utf-8'))
    
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),Myserver)
        server.serve_forever()
    

      Client端:

    import socket
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))
    sk.send('人生苦短,请用Python!'.encode('utf-8'))
    sk.close()
    

      执行结果:

    人生苦短,请用Python!
    

     

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

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

     

    七、UDPServer 实例

      server:

    import socketserver
    
    class MyUDPHandler(socketserver.BaseRequestHandler):
        """
        This class works similar to the TCP handler class, except that
        self.request consists of a pair of data and client socket, and since
        there is no connection the client address must be given explicitly
        when sending data back via sendto().
        """
    
        def handle(self):
            data = self.request[0].strip()
            socket = self.request[1]
            print("{} wrote:".format(self.client_address[0]))
            print(data)
            socket.sendto(data.upper(), self.client_address)
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999
        with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
            server.serve_forever()
    

      

      client:

    import socket
    import sys
    
    HOST, PORT = "localhost", 9999
    data = " ".join(sys.argv[1:])
    
    # SOCK_DGRAM is the socket type to use for UDP sockets
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    # As you can see, there is no connect() call; UDP has no connections.
    # Instead, data is directly sent to the recipient via sendto().
    sock.sendto(bytes(data + "
    ", "utf-8"), (HOST, PORT))
    received = str(sock.recv(1024), "utf-8")
    
    print("Sent:     {}".format(data))
    print("Received: {}".format(received))
    

      

  • 相关阅读:
    gitlab
    MySQL千万级别大表,你要如何优化?
    kafka入门
    zookeeper的原理和应用
    MySQL 性能优化之慢查询
    Redis一些新的看法
    mysql 数据库锁
    MYSQL查看进程和kill进程
    hadoop批量命令脚本xcall.sh及jps找不到命令解决
    java stream 处理分组后取每组最大
  • 原文地址:https://www.cnblogs.com/Felix-DoubleKing/p/9875152.html
Copyright © 2011-2022 走看看