import socketserver '''服务端''' '''tcp版''' # class Myserver(socketserver.BaseRequestHandler): # 必须继承BaseRequestHandler这个类,目的是调用自定义handle()方法 # def handle(self): # 必须自定义一个handle()方法, # print('conn is:', self.request) # self.request=conn # print('addr is:', self.client_address) # self.client_address=addr # # while True: # 通信循环 # try: # data = self.request.recv(1024) # if not data: break # print('客户端发送的消息:', data.decode('utf-8'), self.client_address) # self.request.sendall(data.upper()) # except Exception: # break # # if __name__ == '__main__': # s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), Myserver) # 多线程的tcp服务端,Myserver相当于是循环链接里套的一个通信循环 # # 相当于从socket()实例化到listen()这个步骤 # # s = socketserver.ForkingTCPServer(('127.0.0.1', 8080), Myserver) # 多进程,系统开销高于多线程,一般用多线程,多进程win系统无法运行 # print(s.server_address) # ('127.0.0.1', 8080) # print(s.RequestHandlerClass) # <class '__main__.Myserver'> # print(Myserver) # <class '__main__.Myserver'> # s.serve_forever() # 文件一运行,首先运行的是socketserver.ThreadingTCPServer(),socketserver.ThreadingTCPServer()是一个类实例化的过程,ctrl+左键查看 # 其源码,先继承了ThreadingMixIn,然后继承了TCPServer;ThreadingMixIn没有__init__方法,那么去找TCPServer,TCPServer定义了4个类数据 # 属性,分别代表套接字家族、tcp协议链接,半链接池及是否重用端口(setsocketopt),TCPServer实例化需要3个参数,有一个是默认参数;('127.0.0.1', 8080) # 参数给了server_address,Myserver参数给了RequestHandlerClass;TCPServer的__init__中有继承父类BaseServer的__init__,且把server_address # 和RequestHandlerClass传给了父类BaseServer的__init__;在BaseServer中的__init__,self.server_address = server_address,self.RequestHandlerClass = RequestHandlerClass, # 也就是说s.server_address=('127.0.0.1', 8080),s.RequestHandlerClass=Myserver;再回到TCPServer的__init__,self.socket就是在实例化socket()①, # 还有一段if代码,bind_and_activate默认为True,此时执行的是try代码块,代码块执行了两个方法self.server_bind()和self.server_activate(), # 一个是绑定ip及端口②,一个是设置半链接池(数量默认为5)③,到这里实例化就已经结束了,可以看到这也是一个完整的tcp建立链接之前的流程; # s.serve_forever(),此方法是在BaseServer中,运行self._handle_request_noblock()在BaseServer,运行self.get_request()在TCPServer, # 然后运行self.socket.accept(),也就是建立链接,得到两个结果,赋值给了request, client_address;回到self._handle_request_noblock()运行self.process_request(request, client_address), # self.process_request(request, client_address)在BaseServer,运行self.finish_request(request, client_address), # finish_request(self, request, client_address)在BaseServer,运行self.RequestHandlerClass(request, client_address, self), # 之前讲到socketserver.ThreadingTCPServer()实例化时Myserver参数给了RequestHandlerClass,那么self.RequestHandlerClass(request, client_address, self) # 相当于是在实例化自己定义的Myserver类;继承了BaseRequestHandler,BaseRequestHandler的__init__需要3个参数,self.request = request, # self.client_address = client_address,self.server = s,还有try代码块,运行self.handle(),此时的handle()运行的是自己定义的Myserver类 # 中的handle()方法,实现了循环通信 '''udp版''' class Myserver_1(socketserver.BaseRequestHandler): def handle(self): print(self.request) # (b'qwe', <socket.socket fd=380, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>) # self.request结果为元组类型,第一个是收到客户端字节类型的消息;第二个是socket()对象,可以根据此来进行发消息通信 data = self.request[0] print('客户端发送的消息是:', data.decode('utf-8')) self.request[1].sendto(data.upper(), self.client_address) # self.client_address是发送方地址信息 if __name__ == '__main__': s1 = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), Myserver_1) s1.serve_forever() # 源码分析总结: # 1.基于tcp的socketserver我们自己定义的类中的 # self.server即套接字对象 # self.request即一个链接 # self.client_address即客户端地址 # 2.基于udp的socketserver我们自己定义的类中的 # self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>) # self.client_address即客户端地址
'''客户端1''' from socket import * ip_port = ('127.0.0.1', 8080) buffer_size = 1024 '''tcp''' # tcp_client = socket(AF_INET, SOCK_STREAM) # # tcp_client.connect(ip_port) # # while True: # data = input('请输入:').strip() # if not data: continue # if data == 'quit': break # tcp_client.sendall(data.encode('utf-8')) # msg = tcp_client.recv(buffer_size) # print('服务端发送的消息:', msg.decode('utf-8')) # tcp_client.close() '''udp''' udp_client = socket(AF_INET, SOCK_DGRAM) while True: msg = input('请输入:').strip() udp_client.sendto(msg.encode('utf-8'), ip_port) data, addr = udp_client.recvfrom(buffer_size) print('服务端回复的消息是:', data.decode('utf-8'))
'''客户端2''' from socket import * ip_port = ('127.0.0.1', 8080) buffer_size = 1024 '''tcp''' # tcp_client = socket(AF_INET, SOCK_STREAM) # # tcp_client.connect(ip_port) # # while True: # data = input('请输入:').strip() # if not data: continue # if data == 'quit': break # tcp_client.sendall(data.encode('utf-8')) # msg = tcp_client.recv(buffer_size) # print('服务端发送的消息:', msg.decode('utf-8')) # tcp_client.close() '''udp''' udp_client = socket(AF_INET, SOCK_DGRAM) while True: msg = input('请输入:').strip() udp_client.sendto(msg.encode('utf-8'), ip_port) data, addr = udp_client.recvfrom(buffer_size) print('服务端回复的消息是:', data.decode('utf-8'))
类继承顺序图示
# server类:处理链接
# BaseServer
# TCPServer
# UDPServer
# UnixStreamServer(Unix平台)
# UnixDatagramServer(Unix平台)
# request类:处理通信
# BaseRequestHandler
# StreamRequestHandler
# DatagramRequestHandler