socketserver实现并发及源码分析

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

while True: print('studying...')
原文地址:https://www.cnblogs.com/xuewei95/p/14808946.html