chapter12.3、SocketServer

SocketServer

socket编程过于底层,编程虽然有套路,但是想要写出健壮的代码还是比较困难的,所以很多语言都对socket底层API进行封装,Python的封装就是——socketserver模块。它是网络服务编程框架,便于企业级快速开发。

SocketServer简化了网络服务器的编写。

它有4个同步类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。

2个Mixin类:ForkingMixIn 和 ThreadingMixIn 类,用来支持异步。

class ForkingUDPServer(ForkingMixIn, UDPServer): pass

class ForkingTCPServer(ForkingMixIn, TCPServer): pass

class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

fork是创建多进程,thread是创建多线程

编程接口

socketserver.BaseServer(server_address, RequestHandlerClass)

需要提供服务器绑定的地址信息,和用于处理请求的RequestHandlerClass类。

RequestHandlerClass类必须是BaseRequestHandler类的子类。

BaseRequestHandler类

它是和用户连接的用户请求处理类的基类,定义为BaseRequestHandler(request, client_address, server)

服务端Server实例接收用户请求后,最后会实例化这个类。

它被初始化时,送入3个构造参数:request, client_address, server自身

以后就可以在BaseRequestHandler类的实例上使用以下属性:

self.request是和客户端的连接的socket对象

self.server是TCPServer实例本身

self.client_address是客户端地址

这个类在初始化的时候,它会依次调用3个方法。子类可以覆盖这些方法。

 

# BaseRequestHandler要子类覆盖的方法
class BaseRequestHandler:
  def __init__(self, request, client_address, server):
    self.request = request
    self.client_address = client_address
    self.server = server
    self.setup()
  try:
    self.handle()
  finally:
    self.finish()
  def setup(self): # 每一个连接初始化
    pass
  def handle(self): # 每一次请求处理
    pass
  def finish(self): # 每一个连接清理
    pass

 

ThreadingTCPServer是异步的,可以同时处理多个连接。

TCPServer是同步的,一个连接处理完了,即一个连接的handle方法执行完了,才能处理另一个连接,且只有主线程。

 

ThreadingTCPServer实现的群聊服务器

Chat 
import socketserver
import threading
import logging
import sys

FORMAT = "%(asctime)s %(thread)s %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO)


class ChatHandle(socketserver.BaseRequestHandler):
    clients = {}  # 记录客户端

    def setup(self):
        super().setup()
        self.even = threading.Event()
        self.clients[self.client_address] = self.request  # 添加客户端

    def finish(self):
        super().finish()
        self.even.set()
        self.clients.pop(self.client_address)  # 删除客户端

    def handle(self):
        super().handle()
        logging.info("{1}:{0}".format(self.request, self.client_address))
        while not self.even.is_set():
            try:
                data = self.request.recv(1024)
            except Exception:
                break
            if data.strip() == b"quit":
                break
            msg = "{}{}".format(self.client_address, data.decode())
            logging.info(msg)
            msg = msg.encode()
            for f in self.clients.values():  # 发送给各个客户端
                f.send(msg)
        print("end")


def main():
    # 建立服务器
    server = socketserver.ThreadingTCPServer(("127.0.0.1", 9999), ChatHandle)
    threading.Thread(target=server.serve_forever, name="server").start()
    try:
        while True:
            cmd = input(">>>")
            if cmd.strip() == "quit":
                server.shutdown()
                break
            print(threading.enumerate())
    except Exception as e:
        print(e)
    except KeyboardInterrupt:
        pass
    finally:
        print("exit")
        sys.exit(0)


if __name__ == '__main__':
    main()
ThreadingTCPServer

 

创建服务器需要几个步骤:

1. 从BaseRequestHandler类派生出子类,并覆盖其handle()方法来创建请求处理程序类,此方法将处理传入请求

2. 实例化一个服务器类,传参服务器的地址和请求处理类

3. 调用服务器实例的handle_request()或serve_forever()方法

4. 调用server_close()关闭套接字

 
 
 
 
 
 

posted on 2018-11-04 18:04  Riper  阅读(108)  评论(0编辑  收藏  举报

导航