Python攻克之路-socketserver模块
SocketServer是python的一个网络服务器框架,可以减少开发人员编写网络服务器程序的工作量。
分析:虽然用Python编写的网络唾弃很方便,但复杂一点的网络唾弃还是使用现成的框架比较好,这样就专心于事务逻辑,而不是套接接字的各种细节,socketserver模块化了编写网络服务程序的任务.同时socketserver模块也是Python标准库中很多服务框架的基础
socketserver模块可以简化网络服务器的编写,Python把网络服务抽象成两个主要的类,一个Server类,用于处理连接相关的网络操作,另外一个则是RequestHandler类,用于处理数据相关的操作.并且提供两个MixIn类,用于扩展Server,实现进程多线程
1.实例
server实现接收多并发
[root@node2 socketserver]# cat server.py #实现有多个client进行连接聊天 #!/usr/local/python3/bin/python3 import socketserver class MyServer(socketserver.BaseRequestHandler): #自定义一个类,而且要继承一个类 def handle(self): #逻辑都放在handle方法中 print("starting server..") while True: conn = self.request #client传过来的sk,相当于conn = sk.accept() print(self.client_address) while True: client_data=conn.recv(1024) #收 print(str(client_data,"utf8")) print('waiting...') conn.sendall(client_data) #发,回写 conn.close() if __name__=='__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1',8091),MyServer) #封装好socket要写的部分,进行调用 server.serve_forever() #启动 [root@node2 socketserver]# cat client.py #!/usr/local/python3/bin/python3 import socket ip_port = ('127.0.0.1',8091) sk = socket.socket() sk.connect(ip_port) print('starting client...') while True: inp = input('>>> ') sk.sendall(bytes(inp,'utf8')) if inp == 'exit': break server_response=sk.recv(1024) print(str(server_response,'utf8')) sk.close()
测试
[root@node2 socketserver]# python3 server.py starting server.. ('127.0.0.1', 54978) starting server.. ('127.0.0.1', 54980) starting server.. ('127.0.0.1', 54982) client1 waiting... client2 waiting... client3 waiting... [root@node2 socketserver]# python3 client.py starting client... >>> client1 client1 [root@node2 socketserver]# python3 client.py starting client... >>> client2 client2 [root@node2 socketserver]# python3 client.py starting client... >>> client3 client3
server实现多并发聊天
[root@node2 socketserver]# cat server.py #!/usr/local/python3/bin/python3 import socketserver class MyServer(socketserver.BaseRequestHandler): def handle(self): print("starting server..") while True: conn = self.request print(self.client_address) while True: client_data=conn.recv(1024) print(str(client_data,"utf8")) print('waiting...') server_response=input(">>> ") ##### conn.sendall(bytes(server_response,"utf8")) conn.sendall(client_data) conn.close() if __name__=='__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1',8098),MyServer) #实际是封装连接 server.serve_forever() #实际是启动逻辑 注:真正实际并发的是ThreadingTCPServer类中继承的ThreadingMixIn,建立连接的过程是继承TCPServer类
2.代码执行过程
a.先加载模块,到加载类,但是并没有被执行
import socketserver class MyServer(socketserver.BaseRequestHandler): #自定义一个类,而且要继承一个类 def handle(self):
b.真正开始执行,实例化出一个对象,实际也是执行init方法
server = socketserver.ThreadingTCPServer(('127.0.0.1',8091),MyServer) #封装好socket要写的部分,进行调用
c. 找到类ThreadingTCPServer,有两个父类ThreadingMinIn, TCPServer
class ThreadingTCPServer(ThreadingMinIn, TCPServer): pass
d.父类TCPServer中有init方法
分析:需要传入参数server_address是ip和port,RequestHandlerClass是类,在init中有创建socket的,而且在TCPServer中,
还有一个父类BaseServer而且还有init方法
(1).BaseServer.__init__(self,server_address,RequestHandlerClass) (2).self.socket = socket.socket(self.address_family,self.socket_type) (3).server_bind绑定ip地址和端口 (4).server_activate侦听端口,默认是5个连接 (5).出现错误会执行server_close(),实际是socket.close()关闭
e.执行server.serve_forever()
(1).调用的是BaseServer类,找到serve_forever,真正执行是self.handle_request_noblock() (2).request, client_address = self.get_request() #request相当于conn,客户端的地址整行代码相当于conn,addr = sk.accept() (3).正常会执行self.process_request(request,client_address) (4).执行process_request(在ThreadingMixIn类,相应的创建多线程 (5).到类BaseSever中的init,self.RequestHandlerClass = RequestHandleClass相当于定到自定义的类MyServer下 (6).handle的执行在于class MyServer(socketserver.BaseRequestHandler)中继承的类socketserver.BaseRequestHandler, 内部就有handle的方法 (7).在BaseRequestHandler中的init方法,执行self.setup(),实际是取决于自定义的方法
f.MyServer中写handle,实际是调用父类中的handle,一旦子类把父类的方法覆盖后,都走子类,当再调用self.handle时,父类中def handle(self):是pass,就会执行子类的MyServer中的方法,子类已经重写了handle方法
g.ThreadingTCPServer类中继承的ThreadingMixIn类的执行
3.SocketServer类
主要5个server类:BaseServer,TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer,除了BaseServer,其他类都能够直接使用
BaseServer: 是一个原生类,对某些方法(如server_bind)进行覆盖(子类重写),有process_request,serve_forever等方法
TCPServer: 继承了BaseServer,然后创建socket,绑定端口和ip等TCP的流程实现
UDPSever: 与TCPServer类似
UnixStreamServer:继承TCPServer类,而且只差一个参数adddress_family = socket.AF_UNIX
UnixDatagramServer:继承UDPServer类,而且只差一个参数adddress_family = socket.AF_UNIX
其他server类:
ForkingMixIn: 创建进程
4.创建一个socketserver的步骤
(1).First, you must create a request handler class by subclassing the BaseRequestHandler class and overriding its
handle() method;this method will process incoming requsts. 重写一个类并继承BaseRequestHandler
(2).Second, you must instantiate one of the server classes, passing it the server's address and the requst handler class.
把参数实例一个对象,并传递参数,也就是调用server类,有一个server类,实际是使用TCPServer,UDPServer,ThreadingTCPServer,ThreadingUDPServer,在这里实例化一个对象
(3).Then,call the handle_request() or serve_forever() method of the server object to process one or many requests.
调用handle_request()和serve_forever()去处理请求
(4).Finally,call server_close() to close the socket. 关闭