TCP服务端

1. 前言

TCP通信章节中,我们介绍了使用socket模块创建TCP服务端的方法。但其实,Python的系统库中也提供了一个TCPServer的实现,这个模块就是SocketServer,在Python3中,该模块改成了socketserver

可以使用以下代码进行兼容:

try:
    import socketserver
except ImportError:
    import SocketServer as socketserver

2. 创建请求处理器

TCPServer类的请求参数,需要传入一个BaseRequestHandler子类作为请求处理器。socketserver模块中实现了两个处理器:StreamRequestHandlerDatagramRequestHandler,分别对应TCP协议和UDP协议。

下面看一个简单的例子:


class EchoRequestHandler(socketserver.StreamRequestHandler):
    '''Echo请求处理器
    '''

    def handle(self):
        print('Recv new connection...')
        buff = b''
        while True:
            c = self.rfile.read(1)
            buff += c
            if c == b'\n':
                self.wfile.write(buff)
                buff = b''

这个例子实现了一个Echo服务器,当用户输入一句话,并发送回车后,Server会将这句话返回给用户。

3. 启动TCP服务器

server = socketserver.TCPServer(('127.0.0.1', 7777), EchoRequestHandler)
server.serve_forever()

启动TCP服务器后,请求可以被正常处理,但是有个问题:只能接受一个连接。这是因为我们使用了一个死循环,而TCPServer本身是单线程的。

其实,只要将TCPServer替换为ThreadingTCPServer就可以了。此时,每个请求会使用一个线程处理,因此不会阻塞请求。

server = socketserver.ThreadingTCPServer(('127.0.0.1', 7777), EchoRequestHandler)
server.serve_forever()

但是ThreadingTCPServer并不适合高并发场景,因为线程的总数是有限的,随着线程数量的增加,性能可能会不断下降。

4. ThreadingTCPServer的实现分析

class ThreadingMixIn:
    """Mix-in class to handle each request in a new thread."""

    # Decides how threads will act upon termination of the
    # main process
    daemon_threads = False

    def process_request_thread(self, request, client_address):
        """Same as in BaseServer but as a thread.

        In addition, exception handling is done here.

        """
        try:
            self.finish_request(request, client_address)
            self.shutdown_request(request)
        except:
            self.handle_error(request, client_address)
            self.shutdown_request(request)

    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 ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

这里使用了mix-in方式,ThreadingMixIn类重写了process_request方法,因此继承自ThreadingMixIn类的子类也重写了这个方法,从而做到对每个请求使用单独的线程处理。

drunkdream.cn 版权所有 粤ICP备17153329号 all right reserved,powered by Gitbook该文件修订时间: 2021-01-07 18:27:03

results matching ""

    No results matching ""