Python使用socketserver建立一个异步TCP服务器
Posted anche
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python使用socketserver建立一个异步TCP服务器相关的知识,希望对你有一定的参考价值。
概述
这篇文章是讲解如何使用socketserver建立一个异步TCP服务器,其中Python版本为3.5.1。
socketserver主要的类
socketserver模块中的类主要有以下几个:
1、BaseServer 包含服务器的核心功能与混合类(mix-in)的钩子功能。这个类主要用于派生,不要直接生成这个类的类对象,可以考虑使用TCPServer和UDPServer类。
2、TCPServer:基本的网络同步TCP服务器
3、UDPServer:基本的网络同步UDP服务器
4、ForkingMixIn:实现了核心的进程化功能,用于与服务器类进行混合(mix-in),以提供一些异步特性。不要直接生成这个类的对象。
5、ThreadingMixIn:实现了核心的线程化功能,用于与服务器类进行混合(mix-in),以提供一些异步特性。不要直接生成这个类的对象。
6、ForkingTCPServer: ForkingMixIn与TCPServer的组合
7、ForkingUDPServer:ForkingMixIn与UDPServer的组合
8、BaseRequestHandler:基本的请求处理类
9、StreamRequestHandler:TCP请求处理类的一个实现
10、DataStreamRequestHandler:UDP请求处理类的一个实现
BaseRequestHandler类
BaseRequestHandler类的实例h可以实现以下方法:
1、h.handle() 调用该方法执行实际的请求操作。调用该函数可以不带任何参数,但是几个实例变量包含有用的值。h.request包含请求,h.client_address包含客户端地址,h.server包含调用处理程序的实例。对于TCP之类的数据流服务,h.request属性是套接字对象。对于数据报服务,它是包含收到数据的字节字符串。
2、h.setup() 该方法在handle()之前调用。默认情况下,它不执行任何操作。如果希望服务器实现更多连接设置(如建立SSL连接),可以在这里实现。
3、h.finish() 调用本方法可以在执行完handle()之后执行清除操作。默认情况下,它不执行任何操作。如果setup()和handle()方法都不生成异常,则无需调用该方法。
官方例程
首先上官方给出的例程:
[python] view plain copy <span style="font-size:14px;">import socket import threading import socketserver class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): def handle(self): data = str(self.request.recv(1024), ‘ascii‘) cur_thread = threading.current_thread() response = bytes("{}: {}".format(cur_thread.name, data), ‘ascii‘) self.request.sendall(response) class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass def client(ip, port, message): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect((ip, port)) sock.sendall(bytes(message, ‘ascii‘)) response = str(sock.recv(1024), ‘ascii‘) print("Received: {}".format(response)) if __name__ == "__main__": # Port 0 means to select an arbitrary unused port HOST, PORT = "localhost", 0 server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) ip, port = server.server_address # Start a thread with the server -- that thread will then start one # more thread for each request server_thread = threading.Thread(target=server.serve_forever) # Exit the server thread when the main thread terminates server_thread.daemon = True server_thread.start() print("Server loop running in thread:", server_thread.name) client(ip, port, "Hello World 1") client(ip, port, "Hello World 2") client(ip, port, "Hello World 3") server.shutdown() server.server_close()</span>
client函数是建立一个客户端,可以不用管它。主要部分是在于主函数,ThreadedTCPServer类和ThreadedTCPRequestHandler类。ThreadedTCPServer类继承了BaseRequestHandler类,ThreadedTCPRequestHandler继承了ThreadingMixIn和TCPServer
正常输入如下:
$ python ThreadedTCPServer.py
Server loop running in thread: Thread-1
Received: Thread-2: Hello World 1
Received: Thread-3: Hello World 2
Received: Thread-4: Hello World 3
增加功能
上面部分主要是讲解官方的例程,下面这一部分是博主自己增加的功能。
1、获取客户端的ip和port
1 [python] view plain copy 2 3 client_addr = [] 4 5 class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): 6 7 def setup(self): 8 ip = self.client_address[0].strip() # 获取客户端的ip 9 port = self.client_address[1] # 获取客户端的port 10 print(ip+":"+str(port)+" is connect!") 11 client_addr.append(self.client_address) # 保存到队列中 12 13 def handle(self): 14 data = str(self.request.recv(1024), ‘ascii‘) 15 cur_thread = threading.current_thread() 16 response = bytes("{}: {}".format(cur_thread.name, data), ‘ascii‘) 17 self.request.sendall(response)
1 [python] view plain copy 2 3 print("\nclient_addr:"+str(client_addr))
1 [python] view plain copy 2 3 class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): 4 5 def setup(self): 6 ip = self.client_address[0].strip() # 获取客户端的ip 7 port = self.client_address[1] # 获取客户端的port 8 print(ip+":"+str(port)+" is connect!") 9 client_addr.append(self.client_address) # 保存到队列中 10 11 def handle(self): 12 while True: # while循环 13 data = str(self.request.recv(1024), ‘ascii‘) 14 if data: # 判断是否接收到数据 15 cur_thread = threading.current_thread() 16 response = bytes("{}: {}".format(cur_thread.name, data), ‘ascii‘) 17 self.request.sendall(response) 18 19 def finish(self): 20 print("client is disconnect!")
1 [python] view plain copy 2 3 client_addr = [] 4 client_socket = [] 5 6 class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): 7 8 def setup(self): 9 ip = self.client_address[0].strip() # 获取客户端的ip 10 port = self.client_address[1] # 获取客户端的port 11 print(ip+":"+str(port)+" is connect!") 12 client_addr.append(self.client_address) # 保存到队列中 13 client_socket.append(self.request) # 保存套接字socket 14 15 def handle(self): 16 while True: # while循环 17 data = str(self.request.recv(1024), ‘ascii‘) 18 if data: # 判断是否接收到数据 19 cur_thread = threading.current_thread() 20 response = bytes("{}: {}".format(cur_thread.name, data), ‘ascii‘) 21 self.request.sendall(response) 22 23 def finish(self): 24 print("client is disconnect!") 25 client_addr.remove(self.client_address) 26 client_socket.remove(self.request)
之后在主函数中通过client_socket队列调用sendall或sendto方法即可。例如我在主函数这样写(已经注释掉client函数调用):
1 [python] view plain copy 2 3 message = bytes("clientTest\n", "ascii") 4 while True: 5 time.sleep(2) 6 if client_addr: 7 client_socket[0].sendall(message)
修改服务器ip地址为空及端口为8080,使用socket调试工具连接该服务器,即可每隔2s接收到「clientTest」字符串。
4、服务器接收客户端数据超时后断开
1 [python] view plain copy 2 3 class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): 4 5 ip = "" 6 port = 0 7 timeOut = 6 # 设置超时时间变量 8 9 def setup(self): 10 self.ip = self.client_address[0].strip() # 获取客户端的ip 11 self.port = self.client_address[1] # 获取客户端的port 12 self.request.settimeout(self.timeOut) # 对socket设置超时时间 13 print(self.ip+":"+str(self.port)+"连接到服务器!") 14 client_addr.append(self.client_address) # 保存到队列中 15 client_socket.append(self.request) # 保存套接字socket 16 17 def handle(self): 18 while True: # while循环 19 try: 20 data = str(self.request.recv(1024), ‘ascii‘) 21 except socket.timeout: # 如果接收超时会抛出socket.timeout异常 22 print(self.ip+":"+str(self.port)+"接收超时!即将断开连接!") 23 break # 记得跳出while循环 24 25 if data: # 判断是否接收到数据 26 cur_thread = threading.current_thread() 27 response = bytes("{}: {}".format(cur_thread.name, data), ‘ascii‘) 28 self.request.sendall(response) 29 30 def finish(self): 31 print(self.ip+":"+str(self.port)+"断开连接!") 32 client_addr.remove(self.client_address) 33 client_socket.remove(self.request)
使用socket调试工具连接该服务器后,不发送任何数据,过了6秒钟后,服务器端主要打印如下数据:
192.168.10.53:26408接收超时!即将断开连接!
192.168.10.53:26408断开连接!
以上是关于Python使用socketserver建立一个异步TCP服务器的主要内容,如果未能解决你的问题,请参考以下文章