python库源码分析_Python标准库源码分析:SocketServer.py**********************8

SocketServer简化了网络服务器的编写。它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。这4个类是同步进行处理的,另外通过ForkingMixIn和ThreadingMixIn类来支持异步。

创建它是BaseRequestHandler的子类并重载其handle()方法。其次,你必须实例化一个服务器类,传入服务器的地址和请求处理程序类。最后,调用handle_request()(一般是调用其他事件循环或者使用select())或serve_forever()。

HTTPServer.__init__(self, *args, **kwargs)

File "/usr/local/lib/python2.6/SocketServer.py", line 402, in __init__

self.server_bind()  File "/usr/local/lib/python2.6/BaseHTTPServer.py", line 108, in server_bind    SocketServer.TCPServer.server_bind(self)  File "/usr/local/lib/python2.6/SocketServer.py", line 413, in server_bind

self.socket.bind(self.server_address)  File "", line 1, in bind

error: [Errno 98] Address already in use

先贴一段示例代码(主要针对ThreadingTCPServer,其它类似):

fromSocketServerimportThreadingTCPServer,StreamRequestHandlerfromtimeimportctimeHOST=''PORT=12345ADDR=(HOST,PORT)classMyRequestHandler(StreamRequestHandler):defhandle(self):print'connected from:',self.client_addressself.wfile.write('[%s] %s'%(ctime(),self.rfile.readline()))tcpServer=ThreadingTCPServer(ADDR,MyRequestHandler)#1print'waiting for connection'tcpServer.serve_forever()#2

1.先分析这一行:tcpServer = ThreadingTCPServer(ADDR, MyRequestHandler)

在源代码在中查找ThreadingTCPServer的定义

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

这里使用了Mix-in技术,字面理解就是给TCP类增加了多线程功能,主体还是TCPServer,继续在源代码在中查找TCPServer的定义

class TCPServer(BaseServer):

暂时先不管BaseServer,分析下构造函数

BaseServer.__init__(self,server_address,RequestHandlerClass)self.socket=socket.socket(self.address_family,self.socket_type)ifbind_and_activate:self.server_bind()self.server_activate()

server_bind()和server_activate()分别调用bind()和listen()函数,熟悉socket编程的应该很清楚

至此,初始化工作就完成了

2.分析:tcpServer.serve_forever()

通过查找TCPServer的定义知道,它本身没有这个成员,这个函数是BaseServer的成员,它的构造函数主要是保存服务器地址ADDR和MyRequestHandler类,下面看函数定义:

def serve_forever(self, poll_interval=0.5):

从字面很容易看出这是一个主循环,还有个时间周期默认为0.5s,主循环主要代码:

whilenotself.__shutdown_request:r,w,e=_eintr_retry(select.select,[self],[],[],poll_interval)ifselfinr:self._handle_request_noblock()

通过不断调用select函数,看看自己是否处于可写状态,如果是就调用_handle_request_noblock(),这里有一个问题select函数操作集合的时候有个要求,要么集合本身是描述符,要么他提供一个fileno()接口,返回一个描述符,查找TCPServer的成员函数确实存在这样一个函数,它返回socket的描述符

下面分析_handle_request_noblock(),一般以下划线开头的函数属于内部函数,有点像C++类里面的private函数,一般不用于外部调用,主要内容就两行:

request,client_address=self.get_request()self.process_request(request,client_address)

get_request()在TCPServer中实现,就是调用accept()函数,返回客户端socket和客户端地址

process_request()也是两行

self.finish_request(request,client_address)###线程阻塞self.shutdown_request(request)

主要就是完成请求,关闭请求。注意函数里面的注释Overridden by ForkingMixIn and ThreadingMixIn.一会儿再分析。finish_request()函数的工作就是将最开始的MyRequestHandler类初始化

3.下面开始分析BaseRequestHandler

因为MyRequestHandler和StreamRequestHandler都没有构造函数,因此finish_request()执行的是BaseRequestHandler的构造函数

self.request=requestself.client_address=client_addressself.server=serverself.setup()try:self.handle()finally:self.finish()

具体setup()函数和finish()函数在StreamRequestHandler中实现,而handle函数由MyRequestHandler实现

setup()和finish()主要是设置和清理读写描述符,以便在handle()中可以进行读写操作

4.之前还提到过一个ThreadingMixIn(ForkingMixIn这个在windows平台不支持)

这个类主要是覆盖了BaseServer的process_request()方法,从而实现多线程,因为在原版的process_request()中,函数会阻塞在finish_request()函数中,从而无法处理多个请求,而多线程版的方法中,finish_request()和shutdown_request()在一个新的线程中完成,从而不会阻塞process_request(),主循环得以继续

总结:到这里整个程序运行过程就分析完了,当然还有一些细节,如模块初始化,主线程清理工作等没有仔细分析,但是本文的主要目的是分析优秀代码的设计思路和实现方法,因此忽略这些细节。SocketServer模块的主要设计思路是将我们平时的socket编程两个主要部分进行了分解,一个是主循环监听过程,一个是具体客户端请求处理过程,两个过程分别对应到Server和Request类,Server和Request又进一步抽象成为BaseServer和BaseRequestHandler,在这两个抽象类中完成了对应处理过程,而这些过程的具体实现则分别在不同的具体类中实现,如socket初始化,绑定连接,接受请求,关闭连接等;使用MixIn技术为BaseServer提供了多线程和多进程特性。

ps:我阅读源代码的主要目的是学习优秀代码的设计方法(好的设计方法总是在不断的做解耦和抽象工作),当然也可以学习到很多实现上的技巧。但是直接阅读源代码往往效率很低,很容易被细节所拖累,因此将程序先运行起来,观察到程序的主干路径是一个比较好的方法,根据主干路径逐步提高抽象层次从而逆向分析出原始顶层设计。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 Python 3.9 版本的标准列表: - abc - aifc - argparse - array - ast - asyncio - asyncore - atexit - audioop - base64 - bdb - binascii - binhex - bisect - builtins - bz2 - cProfile - calendar - cgi - cgitb - chunk - cmath - cmd - code - codecs - codeop - collections - collections.abc - colorsys - compileall - concurrent - configparser - contextlib - contextvars - copy - copyreg - crypt - csv - ctypes - curses - dataclasses - datetime - dbm - decimal - difflib - dis - distutils - doctest - email - encodings - ensurepip - enum - errno - faulthandler - fcntl - filecmp - fileinput - fnmatch - formatter - fractions - ftplib - functools - gc - getopt - getpass - glob - grp - gzip - hashlib - heapq - hmac - html - http - hyperlinks - imaplib - imghdr - importlib - inspect - io - ipaddress - itertools - json - keyword - lib2to3 - linecache - locale - logging - lzma - mailbox - mailcap - marshal - math - mmap - modulefinder - msilib - multiprocessing - netrc - nis - nntplib - numbers - opcode - operator - optparse - os - os.path - parser - pathlib - pdb - pickle - pickletools - pipes - pkgutil - platform - plistlib - poplib - pprint - profile - pstats - pty - py_compile - queue - quopri - random - re - readline - reprlib - resource - rlcompleter - runpy - sched - secrets - select - selectors - shelve - shlex - shutil - signal - site - smtpd - smtplib - sndhdr - socket - socketserver - sqlite3 - ssl - stat - statistics - string - stringprep - struct - subprocess - sunau - symbol - symtable - sys - sysconfig - syslog - tabnanny - tarfile - telnetlib - tempfile - termios - test - textwrap - threading - time - timeit - tkinter - token - tokenize - traceback - tracemalloc - tty - turtle - types - typing - unicodedata - unittest - urllib - uu - uuid - venv - warnings - wave - weakref - webbrowser - winreg - winsound - wsgiref - xdrlib - xml - xmlrpc - zipapp - zipfile - zipimport - zlib

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值