15.3. socketserver编程

socketserver在内部使用IO多路复用以及多线程/进程机制,实现了并发处理多个客户端请求的socket服务端。每个客户端请求连接到服务器时,socketserver服务端都会创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。
socketserver模块中使用的服务器类主要有:
    TCPServer       #TCP协议的服务类
    UDPServer       #TCP协议的服务类
    ThreadingTCPServer      #多线程服务器类
    ThreadingUDPServer
    ForkingTCPServer        #多进程服务器类
    ForkingUDPServer

15.3.1. 使用ThreadingTCPServer的要点:

  • 创建一个继承自socketserver.BaseRequestHandler的类;

  • 这个类中必须定义一个名字为handle的方法,不能是别的名字!

  • 将这个类,连同服务器的ip和端口,作为参数传递给ThreadingTCPServer()构造器

  • 手动启动ThreadingTCPServer。

15.3.2. ThreadingTCPServer 示例

服务端 1

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socketserver

class MyServer(socketserver.BaseRequestHandler):
    """
    必须继承socketserver.BaseRequestHandler类
    """
    def handle(self):
        """
        必须实现这个方法!
        :return:
        """
        conn = self.request         # request里封装了所有请求的数据
        conn.sendall('欢迎访问socketserver服务器!'.encode())
        while True:
            data = conn.recv(1024).decode()
            if data == "exit":
                print("断开与%s的连接!" % (self.client_address,))
                break
            print("来自%s的客户端向你发来信息:%s" % (self.client_address, data))
            conn.sendall(('已收到你的消息<%s>' % data).encode())

if __name__ == '__main__':
    # 创建一个多线程TCP服务器
    server = socketserver.ThreadingTCPServer(('127.0.0.1', 9999), MyServer)
    print("启动socketserver服务器!")
    # 启动服务器,服务器将一直保持运行状态
    server.serve_forever()

服务器 2

#!/usr/bin/env python
#-*- coding:utf8 -*-
'''
TCPServer
UDPServer
ThreadingTCPServer
ThreadingUDPServer

socketserver模块中使用的处理器类主要有StreamRequestHandler(基于TCP协议的)和DatagramRequestHandler(基于UDP协议的)
三个方法:
setup()     #为请求准备请求处理器(请求处理的初始化工作)
handler()       #完成具体的请求处理工作(解析请求、处理数据、发出响应)
finish()        #清理请求处理器相关数据
一般,自定义一个简单的请求处理器,只需覆盖handler()方法即可
'''
import socketserver
HOST = "localhost"
PORT = 10888

class MyTcpHandler(socketserver.StreamRequestHandler):
    '''
    定义了一个继承自StreamRequestHandler的处理器类,覆盖了handler()方法
    然后实例化TCPServer类,调用serve_forever()方法启动服务器
    '''
    def handle(self):
        while True:
            data = self.request.recv(1024)
            if not data:
                Server.shutdown()
                break
            print("Receive Data:", data.decode('utf-8'))
            self.request.send(data)
        return
Server = socketserver.TCPServer((HOST,PORT),MyTcpHandler)
Server.serve_forever()

客户端

  • 客户端和socket一样,保持不变

#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
客户端依然使用socket模块就可以了,不需要导入socketserver模块
"""

import socket

ip_port = ('127.0.0.1', 9999)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)
data = sk.recv(1024).decode()
print('服务器:', data)
while True:
    inp = input('你:').strip()
    if not inp:
        continue

    sk.sendall(inp.encode())

    if inp == 'exit':
        print("谢谢使用,再见!")
        break
    data = sk.recv(1024).decode()
    print('服务器:', data)
sk.close()

15.3.3. 服务器端的代码,核心要点

  • 连接数据封装在self.request中!调用send()和recv()方法都是通过self.request对象。

  • handle()方法是整个通信的处理核心,一旦它运行结束,当前连接也就断开了(但其他的线程和客户端还正常),因此一般在此设置一个无限循环。

  • 注意server = socketServer.ThreadingTCPServer((‘127.0.0.1’,8009),MyServer)中参数传递的方法。

    server.serve_forever()表示该服务器在正常情况下将永远运行。 socketserver模块还提供了ThreadingUDPServer类,用于提供多线程的UDP服务。还有ForkingTCPServer类,当操作系统支持fork操作的时候,可以实现多进程服务器。他们的用法和ThreadingTCPServer基本类似