socketserver Module Introduction

A, socketserver module Introduction

socketserver module simplifies network programming, the service class has five modules: BaseServer, TCPServer, UDPServer, UnixStreamServer, UnixDatagramServer. The five categories of relationship are as follows:

+------------+
| Base Server |
+------------+
      |
      v
+-----------+        +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+        +------------------+
      |
      v
+-----------+        +--------------------+
| UDPServer |------->| UnixDatagramServer |

1, four basic synchronization server class profile: 

class socketserver.TCPServer (server_address, RequestHandlerClass, bind_and_activate = True): TCP data stream server
class socketserver.UDPServer (server_address, RequestHandlerClass, bind_and_activate = True): UDP datagram server

class socketserver.UnixStreamServer (server_address, RequestHandlerClass, bind_and_activate = True): limited to Unix systems, Unix socket stream
class socketserver.UnixDatagramServer (server_address, RequestHandlerClass, bind_and_activate = True): limited to Unix systems, Unix datagrams

They have the same meaning of the parameters, as follows:

server_address: address of the server, he should be a tuple comprising the address and port as :( '192.168.1.1', 9000),

RequestHandlerClass: our custom class, the class must override handle () method. Processing all requests for socket.

bind_and_activate: If True, will automatically call server_bind () and server_activate ().

 This process can only run four classes a request, that is, a server can only correspond to a client, which for us in the future to write FTP server may not apply, because we want a service can handle multiple clients, the following Let's look at two asynchronous processing socketserver provide us with class.

2, asynchronous server class Introduction

class socketserver.ForkingMixIn: Enable multi-process
class socketserver.ThreadingMixIn: Enable multi-threaded

Create an asynchronous service method is very simple, create the following TCP framework of a simple example:

import socketserver

class MyTCPServer (of SocketServer.BaseRequestHandler):   # Custom TCP service class must inherit of SocketServer.BaseRequestHandler 
    DEF handle (Self):   # rewrite this class, 
        '' '
        We are dealing with the task
        :return: 
        '' ' 
        Self.fun ()   # carry out our mission 
    DEF Fun (Self):
         Print ( ' the Hello World ' )

class ThreadingTCPServer (socketserver.ThreadingMixIn, SocketServer.TCPServer): # class name easily play, we must inherit two classes 
    Pass 
IF  __name__ == " __main__ " :
    ip_port = ( " 127.0.0.1 " , 9000)   # TCP server address and port

    with socketserver.ThreadingTCPServer(ip_port, MyTCPServer) as server:
        server.serve_forever ()   # open TCP service

So we created a simple asynchronous TCP server framework, in fact ThreadingTCPServer this class we do not have to be created because socketserver has been created for us, as follows:

class ForkingUDPServer (ForkingMixIn, UDPServer): Pass   # multiprocess UDP server 
class ForkingTCPServer (ForkingMixIn, TCPServer): Pass   # multi-process TCP server 
class ThreadingUDPServer (ThreadingMixIn, UDPServer): Pass   # multithreading UDP server 
class ThreadingTCPServer (ThreadingMixIn, TCPServer): Pass   # multi-threaded TCP server

If you think socketserver provided by these four classes not what you want, then you can own definition as above as above are service class, service class by instantiating the object, but the object is not known what methods have, because these service classes are inherited BaseServer class, the methods are BaseServer class, some methods only defines the interface, implemented in sub-class.

3, clients commonly used method

class socketserver.BaseServer(server_address, RequestHandlerClass):

fileno (): Returns the server is listening socket file descriptor (int type number). This function is most commonly passed to the selectors to allow monitoring multiple servers in the same process.

handle_request (): a single request. This function calls the following methods in the order: get_request (), verify_request () and process_request (). If the user handler classes provided handle () method throws an exception, then the server calls handle_error () method. If the request is not received within the timeout seconds, the call to the handle_timeout (), and returns handle_request ().

serve_forever (poll_interval = 0.5) : regular tasks, usually a thread, every second poll_interval polls until stop call shutdown.

service_actions (): This function is serve_forever timer function is called repeatedly, this way we can inherit BaseServer, then override this method.

shutdown (): This method is used to stop the timing task serve_forever ().

socket: socket object.

socket_type: socket socket type, TCP, UDP and so on.

allow_reuse_address: server whether to allow reuse of addresses. The default is false, and can be changed in a subclass.

address_family: Set Socket socket family.

server_address: value is a tuple, socket server address and listen port.

server_activate (): Server will be in a listening state, this function can be rewritten, in fact, his interior is self.socket.listen (self.request_queue_size).

server_bind (): the socket bound to the address can be overwritten.

get_request (): the premise of this method is the need of receiving a request from the socket, it returns a tuple (in communication with the new client socket object, the client address). In fact, the approach is the result self.socket.accept () returns.

server_close (): Close service (closed socket), this method can be rewritten.

RequestHandlerClass: Value is the class name, the class is used to create instances we define our request processing, as described above TCP asynchronous frame MyTCPServer, this class is the value of RequestHandlerClass.

request_queue_size: a request queue size. If a single request takes a long time, when the server is busy the request will be placed in the queue, when the request reaches the value of request_queue_size. Further requests from the client will get a "connection reject" error. The default value is usually 5, but this value can be overridden by a subclass.

finish_request (request, client_address): This method instantiates RequestHandlerClass and call its handle () method to actually process the request.

process_request(request,client_address):调用finish_request()来创建RequestHandlerClass的一个实例。我们可以自己创建线程池或进程池来调用这个函数,实现服务器处理多个请求的问题,ForkingMixIn和ThreadingMixIn类就是这样做的。

handle_error(request,client_address):如果RequestHandlerClass实例的handle()方法引发异常,则调用此函数。默认操作是将回溯打印到标准错误,并继续处理其他请求。在版本3.6中更改:现在仅调用从Exception类派生的异常。

timeout:超时时间(以秒为单位),如果是None,会一直阻塞。如果设置了timeout,handle_request()在超时期间没有收到传入请求,则调用handle_timeout()方法。

handle_timeout():当timeout属性被设置为None以外的值,并且超时周期已经过去而没有收到任何请求时,将调用此函数。多进程 服务器的默认操作是收集已退出的任何子进程的状态,而在线程服务器中,此方法不执行任何操作。

verify_request(request,client_address):返回一个布尔值;如果值为真,请求将被处理,如果值为假,请求将被拒绝。可以重写此函数以实现服务器的访问控制。默认实现只是一句return True。

上面这些都是服务对象的方法,下面来介绍处理socket请求类BaseRequestHandler。

4、客户端请求处理类BaseRequestHandler

class socketserver.BaseRequestHandler:

这是所有socket请求处理程序的基类。它只定义了接口,而没有实现,如果想要使用接口,我们首先继承BaseRequestHandler,然后在子类中重写这些方法。每个socket请求处理程序子类必须重写handle()方法,因为该方法是用于处理所有socket请求。该类的方法如下:

setup():在handle()方法之前调用,执行初始化操作。 默认不执行任何操作,我们可以重写此方法来实现程序的初始化。

handle():所有socket请求任务都是在这个函数内部完成的,我们在子类中必须重写此方法,并处理socket请求,因为默认基类中的handle()的实现不执行任何操作。

finish():在handle()方法之后调用以执行清理操作。默认实现不执行任何操作。如果setup()引发异常,则不会调用此函数。

虽然上面的接口都只是定义而没有实现,但是它的实例属性还是很有用的;

self.request;客户端和服务端的连接对象,用于发送数据,接收数据。 

self.client_address:socket客户端地址 。

self.server:socket服务端信息。

class socketserver.StreamRequestHandler
class socketserver.DatagramRequestHandler
这两个类是socketserver继承BaseRequestHandler后重写了setup(),finish(),实现了对读,写缓冲区的设置,有兴趣的可以看看源码。

5、官方示例:

TCP同步服务示例:

# 服务端
import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):  # 自定义类,继承BaseRequestHandler,处理socket请求

    def handle(self):  # socket客户端请求
        self.data = self.request.recv(1024).strip()  # 接收socket客户端发来的数据
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        self.request.sendall(self.data.upper())  # 将数据大写后发给客户端
'''
class MyTCPHandler(socketserver.StreamRequestHandler):  
    # 自定义类,功能与上面的一样,只不过是继承StreamRequestHandler
    def handle(self):
        # self.rfile is a file-like object created by the handler;
        # we can now use e.g. readline() instead of raw recv() calls
        self.data = self.rfile.readline().strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        # Likewise, self.wfile is a file-like object used to write back
        # to the client
        self.wfile.write(self.data.upper())
'''

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        server.serve_forever()  # 启用TCP服务器
# 打印内容如下
127.0.0.1 wrote:
b'Hello World'

# 客户端
import socket
import sys

HOST, PORT = "localhost", 9999
data = "Hello World"

# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    # Connect to server and send data
    sock.connect((HOST, PORT))
    sock.sendall(bytes(data + "\n", "utf-8"))

    # Receive data from the server and shut down
    received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(data))
print("Received: {}".format(received))

# 打印内容如下
Sent:     Hello World
Received: HELLO WORLD

UDP服务示例:

# 服务端
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()
# 打印内容如下
127.0.0.1 wrote:
b'Hello World'

# 客户端
import socket
import sys

HOST, PORT = "localhost", 9999
data = "Hello World"

# 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 + "\n", "utf-8"), (HOST, PORT))
received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(data))
print("Received: {}".format(received))
# 打印内容如下
Sent:     Hello World
Received: HELLO WORLD

 TCP服务异步示例:

import socket
import threading
import socketserver

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):  # 自定义socket请求处理类
    def handle(self):
        data = str(self.request.recv(1024), 'ascii')
        cur_thread = threading.current_thread()
        response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
        self.request.sendall(response)

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):  # 自定义线程类处理多个请求
    pass

def client(ip, port, message):
    '''
    socket客户端
    :param ip: 服务段的IP地址
    :param port: 服务端的端口
    :param message: 给服务端发送的消息
    :return:
    '''
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect((ip, port))
        sock.sendall(bytes(message, 'ascii'))
        response = str(sock.recv(1024), 'ascii')
        print("Received: {}".format(response))

if __name__ == "__main__":

    HOST, PORT = "localhost", 0  # 端口是0随机获取一个未被使用的端口
    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    with server:
        ip, port = server.server_address  # 获取服务端的IP地址和端口号
        server_thread = threading.Thread(target=server.serve_forever) # 创建线程对象
        server_thread.daemon = True  # 守护线程
        server_thread.start()  # 开启线程,在线程中开启TCP服务器
        print("Server loop running in thread:", server_thread.name)
        # 模拟三个socket客户端连接TCP服务器
        client(ip, port, "Hello World 1")
        client(ip, port, "Hello World 2")
        client(ip, port, "Hello World 3")

        server.shutdown()
# 打印内容如下:
Server loop running in thread: Thread-1
Received: Thread-2: Hello World 1
Received: Thread-3: Hello World 2
Received: Thread-4: Hello World 3

 

参考文档:https://docs.python.org/3/library/socketserver.html?highlight=socketserver#module-socketserver


Guess you like

Origin www.cnblogs.com/caesar-id/p/12094529.html