我们之前例子都是一个服务端同时只能接受一个客户端的请求,而我们实际的情况是,一个服务端可能要应对上百上千个客户端的请求。而这样的需求就只能通过多进程或者多线程的方法来进行实现,多线程和多进程具体是怎么实现,我们先不做深入探究,先看一个简单的多线程的实例。
实现代码
- 服务端
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
print('conn is:',self.request)
print('addr is:',self.client_address)
while True:
#收消息
data=self.request.recv(1024)
print('收到的客户端消息是',data)
#发消息
self.request.sendall((data.upper()))
if __name__ == '__main__':
s = socketserver.ThreadingTCPServer(('127.0.0.1',8001),MyServer)
s.serve_forever()
客户端的代码使用上两节最普通的基础代码即可,现在我们详解一下这个服务端的代码。
代码实现逻辑
socketserver模块中所定义的几个类的继承关系。
- ThreadingTCPServer --> TCPServer --> BaseServer
- ThreadingTCPServer --> ThreadingMixIn
然后我们就来看看上面的代码,每一步是如何实现的
- 1、产生实例
s = socketserver.ThreadingTCPServer(('127.0.0.1',8001),MyServer)
这一步是生成了一个实例s,这个实例是由ThreadingTCPServer这个类产生的,查询此模块的源代码。
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
可见此类源代码中没有任何特殊属于自己的方法以及属性,全部继承于ThreadingMixIn和TCPServer,那我们继续查看TCPServer的源代码。
- 2、TCPServer类的初始化
class TCPServer(BaseServer):
#套接字的地址家族
address_family = socket.AF_INET
#套接组的类型
socket_type = socket.SOCK_STREAM
#套接字的队列长度
request_queue_size = 5
#禁止地址重用
allow_reuse_address = False
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
try:
self.server_bind()
self.server_activate()
except:
self.server_close()
raise
从上述代码中发现初始化传入的参数是self,server_address,RequestHandlerClass,那对应代码中的就是实例s,(‘127.0.0.1’,8001)以及MyServer这个我们自己定义的请求接收类。
TcpServer类会调用父类BaseServer的init方法,主要是将两个参数的值保存在实例属性中。
class BaseServer:
def __init__(self, server_address, RequestHandlerClass):
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
- 3、地址绑定
接下来,实例会产生一个套接字对象,同时将地址和端口进行绑定并进行监听。其中用到两个方法server_bind()和server_activate(),本质上就是socket模块的bind和listen的封装。这两个方法都属于TcpServer
def server_bind(self):
if self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname()
def server_activate(self):
self.socket.listen(self.request_queue_size)
至此初始化的步骤就已经结束,套接字已经开始监听。
- 5、执行s.serve_forever()方法
这个方法是属于BaseServer类下面的方法
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
其中由很多涉及线程的知识,我们着重_handle_request_noblock()这个方法入手
def _handle_request_noblock(self):
try:
request, client_address = self.get_request() #conn,clientaddress
except OSError:
return
if self.verify_request(request, client_address):
#判断request, client_address是否为空
try:
self.process_request(request, client_address)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)
else:
self.shutdown_request(request)
其中get_get_request()这个方法是TCPServer类中的一个方法,会返回self.socket.accept()这个方法的结果,而这个套接字方法我们知道会返回两个结果,一个conn对象和客户端地址。
因此request就是conn对象,client_address就是客户端地址。
判断两者若不为空,则会执行process_request方法
def process_request(self, request, client_address):
self.finish_request(request, client_address)
self.shutdown_request(request)
def finish_request(self, request, client_address):
self.RequestHandlerClass(request, client_address, self)
而这个RequestHandlerClass就是我们自己写的代码中的Myserver类(类实例初始化的时候忘记了self.RequestHandlerClass = RequestHandlerClass有这么一行代码吗),所以s.serve_forever最后相当于是在运行s.Myserver类的代码
- 6、运行Myserver类代码
class MyServer(socketserver.BaseRequestHandler)
Myserver类继承于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()
在对这个类进行初始化的时候,就会运行handle方法。而我们自定义的handle方法就会开始运转,进入收发消息的循环中。