import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
try:
while True:
self.data=self.request.recv(1024)
print("{} send:".format(self.client_address),self.data)
if not self.data:
print("connection lost")
break
self.request.sendall(self.data.upper())
except Exception as e:
print(self.client_address,"连接断开")
finally:
self.request.close()
def setup(self):
print("before handle,连接建立:",self.client_address)
def finish(self):
print("finish run after handle")
if __name__=="__main__":
HOST,PORT = "localhost",9999
server=socketserver.TCPServer((HOST,PORT),MyTCPHandler)
server.serve_forever()
import socket
client=socket.socket()
client.connect(('localhost',9999))
while True:
cmd=input("(quit退出)>>").strip()
if len(cmd)==0:
continue
if cmd=="quit":
break
client.send(cmd.encode())
cmd_res=client.recv(1024)
print(cmd_res.decode())
client.close()
使用ThreadingTCPServer:
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
try:
while True:
self.data=self.request.recv(1024)
print("{} send:".format(self.client_address),self.data)
if not self.data:
print("connection lost")
break
self.request.sendall(self.data.upper())
except Exception as e:
print(self.client_address,"连接断开")
finally:
self.request.close()
def setup(self):
print("before handle,连接建立:",self.client_address)
def finish(self):
print("finish run after handle")
HOST,PORT = "localhost",9999
server=socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)#多线程版
server.serve_forever()
ThreadingTCPServer的类图关系如下:
内部调用流程为:
ThreadingTCPServer相关源码:
class BaseServer:
def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
#poll_interval表示select轮询的时间
# serve_forever函数,创建server对象之后我们会使用server对象开启无限循环,
# 接受一个参数poll_interval,用于表示select轮询的时间,
# 然后进入一个死循环,用select方法进行网络IO的监听,
# 这里通过调用selector.register(self, selectors.EVENT_READ)进行了注册,
# 当ready有返回是,表示有IO连接或者数据,这个时候会调用_handle_request_noblock
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or connecting to the
# socket to wake this up instead of polling. Polling reduces our
# responsiveness to a shutdown request and wastes cpu at all other
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)#检测是否注册
while not self.__shutdown_request:
ready = selector.select(poll_interval) #进行网络IO的监听
if ready:
self._handle_request_noblock()#开始处理一个请求,并且是非阻塞
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
# Decides how threads will act upon termination of the
# main process
daemon_threads = False
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
In addition, exception handling is done here.
"""
try:
self.finish_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
finally:
self.shutdown_request(request)
#MixIn子类通过重写该方法,进行多线程或多进程的配置
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start()
SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 Threading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。
ForkingTCPServer和ThreadingTCPServer的使用和执行流程基本一致,只不过在内部分别为请求者建立 “线程” 和 “进程”。
基本使用:
import SocketServer
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
pass
if __name__ == '__main__':
server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()