3.1.3 SocketServer模块源码剖析

SocketServer()简介

socketserver()最主要的作用就是实现Socket的并发处理。

socketserver()简化了编写网络服务器的开发。

简单来说,socketserver()就是对socket()的一个再封装,有以下四种基本类型(以下内容引自官方文档):

  • TCPServer uses the Internet TCP protocol, which provides for continuous streams of data between the client and server.
  • UDPServer uses datagrams, which are discrete packets of information that may arrive out of order or be lost while in transit.
  • The more infrequently used UnixStreamServer and UnixDatagramServer classes are similar, but use Unix domain sockets; they’re not available on non-Unix platforms.

译文:

  • TCPServer使用TCP互联网协议,在客户端和服务器端提供持续稳定的数据流。
  • UDPServer使用数据报协议,这些不相连的数据包在传送中可能会丢失或者打乱顺序。
  • 更加不常用的两种,UnixStreamServer和UnixDatagramServer,这两种很相似,但都使用Unix域套接字;这两种类型在非Unix平台上不能使用。

These four classes process requests synchronously; each request must be completed before the next request can be started. This isn’t suitable if each request takes a long time to complete, because it requires a lot of computation, or because it returns a lot of data which the client is slow to process. The solution is to create a separate process or thread to handle each request; the ForkingMixIn and ThreadingMixIn mix-in classes can be used to support asynchronous behaviour.

以上四种类型的socketserver都是同步处理请求;每一个请求必须在下一个请求开始之前处理完毕。如果每个请求需要花很长时间才能处理完毕那么这样肯定不合适,因为这将需要大量的计算或者将返回大量的数据,这样客户端处理起来会很慢。解决方案是创建一个独立的进程或线程以解决每一个请求;ForkingMixIn和ThreadingMixIn这种混合类型可以被用来支持异步传输。

There are five classes in an inheritance diagram, four of which represent synchronous servers of four types:

继承图中有五个类,其中四个代表了四种类型的同步服务器:

+------------+
| BaseServer |
+------------+
      |
      v
+-----------+        +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+        +------------------+
      |
      v
+-----------+        +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+        +--------------------+

Creating a server requires several steps.

First, you must create a request handler class by subclassing the BaseRequestHandler class 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.

Finally, call the handle_request() or serve_forever() method of the server object to process one or many requests.

创建一个服务器端需要以下几步:

首先,你必须创建一个请求处理类,并且这个类要继承BaseRequestHandler类,并重写BaseRequestHandler类里的handle()方法;这个方法会处理正在进入的请求。

第二,你必须实例化一个服务器类,并将服务器的地址和上面的请求处理类传给它。

最后,调用服务器对象的handle_request()或serve_forever()方法以处理一个或多个请求。

下面实现一个最简单的SocketServer:

服务器端

import socketserver

class MyTcpHandler(socketserver.BaseRequestHandler):    #这就是那个请求处理类
    def handle(self):    #重写handle()方法
        while True:    #循环收发数据
            try:
                self.data = self.request.recv(1024).strip()    #接收数据
                print('{} wrote: '.format(self.client_address[0]))
                print(self.data)
                self.request.send(self.data.upper())
            except Exception as e:    #抓取报错
                print('Error: ', e)
                break    #不加break会无限循环报错

if __name__ == '__main__':
    host, port = 'localhost', 9999
    server = socketserver.TCPServer((host, port), MyTcpHandler)
    #这就是第二步说的服务器类的实例
    server.serve_forever()

客户端

import socket

client = socket.socket()    #生成一个套接字对象
HOST = ‘localhost’    #获取本机主机名
PORT = 9999
client.connect((HOST, PORT))

while True:    #加一个循环,让客户端可以不断的发送数据
    msg = input('>>> ').strip()
    if len(msg) == 0:    #不加这个判断,发送数据为空,程序会卡住
        continue
    client.send(msg.encode('utf-8'))    #发送数据,在python3.x中,只能发送bytes类型的数据
    data = client.recv(1024)         #设定接收数据的大小,单位是字节
    print('recv: ', data)

输出结果

服务器端

127.0.0.1 wrote: 
b'1'
127.0.0.1 wrote: 
b'2'
127.0.0.1 wrote: 
b'3'
127.0.0.1 wrote: 
b'4'
Error:  [WinError 10054] 远程主机强迫关闭了一个现有的连接。

客户端

>>> 1
recv:  b'1'
>>> 2
recv:  b'2'
>>> 3
recv:  b'3'
>>> 4
recv:  b'4'
>>> 断开操作

示例完成,但以上示例依然无法进行多并发处理连接请求。要实现多并发处理其实很简单,只需要将服务器端的这句

server = socketserver.TCPServer((host, port), MyTcpHandler)

中的TcpServer改成ThreadingMixIn就行了,多线程会在后面学习到,这里暂不探讨。

下面是SocketServer对象的定义,引自官方文档,日后有空再翻译吧:

Server Objects

socketserver.fileno()

Return an integer file descriptor for the socket on which the server is listening. This function is most commonly passed to select.select(), to allow monitoring multiple servers in the same process.

socketserver.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 self.timeout seconds, handle_timeout() will be called and handle_request() will return.

socketserver.serve_forever(poll_interval=0.5)

Handle requests until an explicit shutdown() request. Polls for shutdown every poll_interval seconds.

socketserver.shutdown()

Tells the serve_forever() loop to stop and waits until it does.

socketserver.address_family

The family of protocols to which the server’s socket belongs. Common examples are socket.AF_INET and socket.AF_UNIX.

socketserver.RequestHandlerClass

The user-provided request handler class; an instance of this class is created for each request.

socketserver.server_address

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.

socketserver.socket

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

The server classes support the following class variables:

socketserver.allow_reuse_address

Whether the server will allow the reuse of an address. This defaults to False, and can be set in subclasses to change the policy.

socketserver.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.

socketserver.socket_type

The type of socket used by the server; socket.SOCK_STREAM and socket.SOCK_DGRAM are two common values.

socketserver.timeout

socketserver. 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.

socketserver.finish_request()

Actually processes the request by instantiating RequestHandlerClass and calling its handle() method.

socketserver.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.

socketserver.handle_error(request, client_address)

This function is called if the RequestHandlerClass‘s handle() method raises an exception. The default action is to print the traceback to standard output and continue handling further requests.

socketserver.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.

socketserver.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.

socketserver.server_activate()

Called by the server’s constructor to activate the server. The default behavior just listen()s to the server’s socket. May be overridden.

socketserver.server_bind()

Called by the server’s constructor to bind the socket to the desired address. May be overridden.

socketserver.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.

RequestHandler Objects

The request handler class must define a new handle() method, and can override any of the following methods. A new instance is created for each request.

socketserver.finish()

Called after the handle() method to perform any clean-up actions required. The default implementation does nothing. If setup() or handle() raise an exception, this function will not be called.

socketserver.handle()

This function must do all the work required to service a request. The default implementation does nothing. Several instance attributes are available to it; the request is available as self.request; the client address as self.client_address; and the server instance as self.server, in case it needs access to per-server information.

The type of self.request is different for datagram or stream services. For stream services, self.request is a socket object; for datagram services, self.request is a pair of string and socket. However, this can be hidden by using the request handler subclasses StreamRequestHandler or DatagramRequestHandler, which override the setup() and finish() methods, and provide self.rfile and self.wfile attributes. self.rfile and self.wfile can be read or written, respectively, to get the request data or return data to the client.

socketserver.setup()

Called before the handle() method to perform any initialization actions required. The default implementation does nothing.






猜你喜欢

转载自www.cnblogs.com/infinitecodes/p/12109039.html