python成长之路10——socketserver源码分析
1 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) 2 3 参数一:地址簇 4 socket.AF_INET ipv4(默认) 5 socket.AF_INET6 ipv6 6 7 socket.AF_UNIX 本地进程间通信 8 9 参数二:类型 10 socket.SOCK_STREAM 流式socket,TCP(默认) 11 socket.SOCK_DGRAM 数据报式socket,UDP 12 socket.SOCK_RAW 原始套接字,ICMP,IGMP 13 socket.SOCK_RDM 可靠的UDP形式 14 socket.SOCK_SEQPACKET 可靠的连续数据包服务 15 16 参数三:协议 17 0 (默认) 与特定地址家族相关的协议,如果是0,则系统会根据地址格式和套接类别,自动选择一个合适的协议 18 19 s.bind(ip_port) 20 s.listen(backlog) backlog:最大挂起数 21 s.setblocking(bool) 是否阻塞(默认为True),如果设为False,那么accept和recv时一旦无数据就会报错 22 s.accept() 默认阻塞的 23 s.connect(ip_port)连接出错会报错 24 s.connect_ex(ip_port) 连接成功返回0,出错返回编码 25 s.close() 26 s.recv(1024) 1024为最多接收的字节 27 s.recvfrom(1024) 返回值是元祖(data,address,)主要用于UDP 28 s.send() 发送的是字节(3.5) 不一定把所有消息都发完 29 s.sendall() 都发完 30 s.sendto(数据,address) 指定远程地址,主要用于UDP协议 31 s.settimeout(timeout) timeout 浮点数 单位秒,None为没有超时期 32 s.getpeername() 返回连接套接字的远程地址 元祖(ip_port)用于TCP 33 s.getsockname() 返回套接字字节的自己的地址 也是元祖 (ip_port) 用于TCP 34 s.fileno() 套接字的文件描述符 35 36 socket功能
上面又复习了一次socket
下面我们开始分析socketserver的源码:
首先先贴出socketserver各类间的继承关系:
以上两个图包含了socketserver里的所有类和函数,方便以后查找他们之间的继承关系!图中“1”代表先继承,“2”代表后继承
现在我们来分析下面这段代码:
#/usr/bin/env python #-*- coding:utf-8 -*- #Authot:Zhang Yan import socketserver ip_port=("127.0.0.1",9999,) class MyServer(socketserver.BaseRequestHandler): def handle(self): pass obj=socketserver.ThreadingTCPServer(ip_port,MyServer) obj.serve_forever()
MyServer类的继承关系如下:
obj=socketserver.ThreadingTCPServer(ip_port,MyServer)
构建obj对象,执行ThreadingTCPServer类的__init__方法,所以obj是ThreadingTCPServer的对象
从下图可以看出执行的是TCPServer里的init方法
查看此段源码:
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): """Constructor. May be extended, do not override.""" BaseServer.__init__(self, server_address, RequestHandlerClass) #在TCPServer的init方法里执行BaseServer的init方法 self.socket = socket.socket(self.address_family, self.socket_type) #构建socket对象 if bind_and_activate: try: self.server_bind() #socket的bind方法 self.server_activate() #socket的listen方法 except: self.server_close() #socket的close方法 raise
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() #执行threading.Event的init方法,构建对象 self.__shutdown_request = False
obj.serve_forever(),因为obj是ThreadingTCPServer的对象,所以先在ThreadTCPServer里找,没有的话在他的父类里找,如下图:
def serve_forever(self, poll_interval=0.5): """Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread. """ 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) if ready: self._handle_request_noblock() #其他地方先不考虑,先看这两行,_handle_request_noblock是BaseServer的私有方法 self.service_actions() #self是obj,是ThreadTCPServer的对象,需要根据继承关系找到service_actions()方法 finally: self.__shutdown_request = False self.__is_shut_down.set()