前言
在学完socket之后,可以实现简单的服务端与客户端的交互,但是基础的socket只能实现一个客户端与一个服务端的交互,并不能实现多个客户端同时与一个服务端进行交互,所以便出现了socketserver模块.
1.socketserver简介
socket模块不能实现并发处理,socketserver是对socket的一个封装,其最主要的作用就是实现并发处理.
socketserver共有以下几种类型:
- TCP协议
class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
- UDP协议
class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
- Unix 本机之间进程的TCP、UDP (不常用)
class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)
注:我们最常用的就是TCP和UDP协议.
类型之间的关系:
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
其中,BaseServer是基类.
2.创建socketserver
我们来看创建一个socketserver需要哪些步骤.
socketserver创建步骤:
- 第一步:必须自己创建一个请求处理类,让这个类继承BaseRequestHandler(),并且重写父类的handle()方法.
- 第二步:必须实例化一个TCPServer(这里以TCPServer为例),并且传递server_ip和上面创建的请求处理类给这个TCPServer对象.
- 第三步:调用handle_request()或者serve_forever()方法来处理一个或多个请求。
handle_request()方法是处理一个请求,我们一般不用这个
server_forever()方法是用来处理多个请求,我们一般用的就是这个
- 第四步:调用server_close()来关闭socket.
3.实现一个简单的SocketServer
在上一个标题中我们知道了创建一个SocketServer的步骤,接下来我们就来实现一个SocketServer.
服务端代码----socketserver_server.py
"""
创建一个socketserver需要以下几个步骤:
1.必须自己创建一个请求处理类,这个类要继承BaseRequestHandler,并且重写父类的handle方法
2.必须实例化一个TCPserver(这是socketserver的一种类型,还有UDPserver),并且传递server_ip和上面创建的请求处理类
3.调用handle_request()或者server_forever()方法来处理一个或多个请求
注:handle_request()是处理一个请求,server_forever()是处理多个请求
4.调用server_close()关闭socket
"""
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler): # 创建自己的一个请求处理类,继承BaseRequestHandler
def handle(self): # 重写handle()函数
# 跟客户端所有的交互都是在handle里完成的
# 每一个请求过来都会实例化MyTCPHandler
print("conn is: ",self.request) # self.request就是socket中的conn
print('addr is: ',self.client_address) # self.client_address就是Socket中的addr
# 接下来就是接收客户端的请求,并且与客户端进行数据交互
while True:
try:
data = self.request.recv(1024)
if not data:
break
print('收到的客户端的消息是:',data.decode())
self.request.sendall(data.upper())
except ConnectionResetError as e:
print('error--',e)
break
if __name__ == '__main__':
server = socketserver.TCPServer(('localhost',9966),MyTCPHandler)
server.serve_forever()
代码解释:
按照socketserver创建流程我们来解释一下代码.
(1) 创建一个自己的请求处理类,这个类要继承BaseRequestHandler:
class MyTCPHandler(socketserver.BaseRequestHandler): # 创建自己的一个请求处理类,继承BaseRequestHandler
(2) 重写BaseRequestHandler类中的handle方法:
def handle(self): # 重写handle()函数
# 跟客户端所有的交互都是在handle里完成的
# 每一个请求过来都会实例化MyTCPHandler
print("conn is: ",self.request) # self.request就是socket中的conn
print('addr is: ',self.client_address) # self.client_address就是Socket中的addr
# 接下来就是接收客户端的请求,并且与客户端进行数据交互
while True:
try:
data = self.request.recv(1024)
if not data:
break
print('收到的客户端的消息是:',data.decode())
self.request.sendall(data.upper())
except ConnectionResetError as e:
print('error--',e)
break
这里需要说明的是:
- 服务端跟客户端的交互都是在这个handle()方法中完成的
- 每一个客户端的请求连接后都会实例化MyTCPHandler
- self.request 就是socket中的conn
- self.client_address 就是socket中的addr
(3) 实例化一个TCPserver,并且传递server_ip和上面创建的请求处理类
server = socketserver.TCPServer(('localhost',9966),MyTCPHandler)
注:这里会传入两个参数,第一个参数是ip和端口,第二个参数是我们创建的请求处理类.
其实还有一个参数bind_and_activate=True,但这个我们现在用不到,我也没有去做研究,也不知道这个参数具体代表什么.有知道的小伙伴可以在评论中分享一下,感谢大家.
(4)调用serve_forever()来处理多个请求
server.serve_forever()
客户端代码----socketserver_client.py
socketserver主要是针对服务端来做的,所以对于客户端代码,并没有太多的改变,就用之前写过的一个代码就可以.
'''
客户端
'''
import socket
client = socket.socket() # 创建Socket对象,声明socket类型
client.connect(('localhost',9966))
while True:
msg = input("请输入: ")
if len(msg) == 0:
continue
client.send(msg.encode('utf-8'))
data = client.recv(1024)
print('客户端接收的数据为: ',data.decode())
client.close()
客户端代码就不做过多解释了.
运行结果:
我们开启一个终端来运行服务端代码,另外开启两个终端,每个终端都运行客户端代码,以此来实现并发的效果.结果如下:
服务端:
客户端1:
客户端2:
警告!
到这里我们发现客户端1正常运行,而客户端2处于等待状态,当客户端1关闭时,客户端2才运行,这个效果和socket也没有区别啊,也没有体现出多并发的效果.
原来啊,要想真正实现并发的效果,只需要改动一个地方就可以.将socketserver.TCPServer改成socketserver.ThreadingTCPServer就可以了.
socketserver.ThreadingTCPServer才是真正实现多并发的socketserver.下面来看效果.
4.实现一个真正多并发的socketserver
服务端代码----socketserver_server.py
"""
创建一个socketserver需要以下几个步骤:
1.必须自己创建一个请求处理类,这个类要继承BaseRequestHandler,并且重写父类的handle方法
2.必须实例化一个TCPserver(这是socketserver的一种类型,还有UDPserver),并且传递server_ip和上面创建的请求处理类
3.调用handle_request()或者server_forever()方法来处理一个或多个请求
注:handle_request()是处理一个请求,server_forever()是处理多个请求
4.调用server_close()关闭socket
"""
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler): # 创建自己的一个请求处理类,继承BaseRequestHandler
def handle(self): # 重写handle()函数
# 跟客户端所有的交互都是在handle里完成的
# 每一个请求过来都会实例化MyTCPHandler
print("conn is: ",self.request) # self.request就是socket中的conn
print('addr is: ',self.client_address) # self.client_address就是Socket中的addr
# 接下来就是接收客户端的请求,并且与客户端进行数据交互
while True:
try:
data = self.request.recv(1024)
if not data:
break
print('收到的客户端的消息是:',data.decode())
self.request.sendall(data.upper())
except ConnectionResetError as e:
print('error--',e)
break
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('localhost',9966),MyTCPHandler) # ThreadingTCPServer才是可以真正的实现多并发
server.serve_forever()
客户端代码----socketserver_client.py
客户端代码不变
'''
客户端
'''
import socket
client = socket.socket() # 创建Socket对象,声明socket类型
client.connect(('localhost',9966))
while True:
msg = input("请输入: ")
if len(msg) == 0:
continue
client.send(msg.encode('utf-8'))
data = client.recv(1024)
print('客户端接收的数据为: ',data.decode())
client.close()
运行结果
服务端:
客户端1:
客户端2:
到这里,我们真正实现了一个多并发的socketserver.