socketserver模块简化了编写网络服务器的任务
有4个基本的服务器类(server class):
socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)
这四个类是同步(Synchronous)进行处理的。要处理异步(Asynchronous),需使用ThreadingMixIn和ForkingMixIn类。
创建服务器需要几个步骤:
- you must create a request handler class by subclassing the BaseRequestHandler class and overriding its handle() method; this method will process incoming requests. 你必须创建一个请求处理类,这个类需继承BaseRequestHandler,并且重写父类的handle方法
- you must instantiate one of the server classes, passing it the server’s address and the request handler class. Then call the handle_request() or serve_forever() method of the server object to process one or many requests. 你必须实例化server classes(如TCPServer),并且传递server address和上面创建的请求处理类给server classes(如TCPServer),然后调用服务器对象(实例化的server classes)的handle_request()或serve_forever()方法来处理一个或多个请求。
- call server_close() to close the socket.调用server_close()关闭套接字。
import socket HOST,PORT = "localhost",9999 with socket.socket() as sock: sock.connect((HOST,PORT)) sock.send("abc".encode()) received = sock.recv(1024).decode() print("sent: {}".format("abc")) print("received:{}".format(received))
import socketserver class MyTcpHandle(socketserver.BaseRequestHandler): #第一步,创建一个请求处理类,并且重写handle def handle(self): #客户端的请求都在handle来实现 #self.request is the TCP socket conneted to le client self.data = self.request.recv(1024).strip() # print("{} wrote:".format(self.client_address)) print(self.data) self.request.send(self.data.upper()) if __name__ == "__main__": HOST,PORT = "localhost",9999 server = socketserver.TCPServer((HOST,PORT),MyTcpHandle) #第二步,实例化服务器类 server.serve_forever()
上面仍不能与多个用户通信,此时我们需要用到异步,即ThreadingMixIn和ForkingMixIn,直接看代码
import socket HOST,PORT = "localhost",9999 with socket.socket() as sock: sock.connect((HOST,PORT)) while True: data = input(">>").strip() if len(data) == 0: continue sock.send(data.encode()) received = sock.recv(1024).decode() print("sent: {}".format(data)) print("received:{}".format(received))
import socketserver import threading,socket class MyTcpHandle(socketserver.BaseRequestHandler): def handle(self): #self.request is the TCP socket conneted to le client while True: try: self.data = self.request.recv(1024).strip() #当客户端没有数据时会产生ConnectionResetError异常 except ConnectionResetError as e: print(e) break print("{} wrote:".format(self.client_address)) print(self.data) self.request.send(self.data.upper()) class ThreadTCPServer(socketserver.ThreadingMixIn,socketserver.TCPServer): pass if __name__ == "__main__": HOST,PORT = "localhost",9999 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTcpHandle) #继承ThreadingMixIn, TCPServer #实例化ThreadingTCPServer其实就是实例化TCPServer((HOST,PORT),MyTcpHandle) server.serve_forever() #最后其实是MyTcpHandle(finish_request中实现)实例化,self.request相当于在套接字中的conn(用户端实例), client_address(用户端地址和端口号)
根据源码分析可得,ThreadindTCPServer继承ThreadMixIn和TCPServer
先看下第一步初始化
server = socketserver.ThreadingTCPServer((HOST,PORT),MyTcpHandle)做了什么操作:
1、通过继承关系知道ThreadingTCPServer初始化就是TCPServer初始化
2、TCPServer初始化里面做了什么操作呢?先继承了BaseServer的构造方法然后初始化生成一个套接字socket,然后bind和listen
3、BaseServer做了什么操作呢?对传进来的两个参数进行初始化分别赋值给:server_address和RequestHandlerClass,生成一个线程事件__is_shut_down=threading.Event来进行同步,对__shutdown_request 赋值False
等学完select和多线程,要来分析下socketserver源码并做记录
第二步:server.serve_forever()
1、使用了事件驱动selectors模块,当有连接进来时,运行_handle_request_noblock()
2、accept得到request,client_address
3、创建一个线程来处理连接过来的请求