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. 关闭