PHP前端开发

python自带的http模块详解

百变鹏仔 2小时前 #Python
文章标签 自带

挺久没写博客了,因为博主开始了今年另一段美好的实习经历,学习加做项目,时间已排满;很感谢今年这两段经历,让我接触了golang和python,学习不同语言,可以跳出之前学习c/c++思维的限制,学习golang和python的优秀特性以及了解在不同的场景,适用不同的语言;而之前学习linux和c/c++,也使我很快就上手golang和python;

我学习的习惯,除了学习如何使用,还喜欢研究源码,学习运行机制,这样用起来才会得心应手或者说,使用这些语言或框架,就和平时吃饭睡觉一样,非常自然;因为最近有接触到bottle和flask web框架,所以想看下这两个的源码,但是这两个框架是基于python自带的http,因此就有了这篇文章;

python http简单例子

python http框架主要有server和handler组成,server主要是用于建立网络模型,例如利用epoll监听socket;handler用于处理各个就绪的socket;先来看下python http简单的使用:

import sysfrom http.server import HTTPServer,SimpleHTTPRequestHandlerServerClass = HTTPServerHandlerClass = SimpleHTTPRequestHandlerif__name__ =='__main__': port = int(sys.argv[2]) server_address = (sys.argv[1],port) httpd = ServerClass(server_address,HandlerClass)sa=httpd.socket.getsockname()print("Serving HTTP on",sa[0],"port",sa[1],"...")try: httpd.serve_forever() except KeyboardInterrupt:print("Keyboard interrupt received, exiting.") httpd.server_close() sys.exit(0)

立即学习“Python免费学习笔记(深入)”;

运行上述例子,可以得到如下:

python3 myhttp.py 127.0.0.1 9999

立即学习“Python免费学习笔记(深入)”;

此时如果在当前文件夹新建一个index.html文件,就可以通过  http://127.0.0.1:9999/index.html 访问了index.html页面了。

这个例子的server类用的是HTTPServer,handler类是SimpleHTTPRequestHandler,因此当HTTPServer监听到有request到来时,就把这个request丢给SimpleHTTPRequestHandler类求处理;ok,了解这些之后,我们开始分别分析下server和handler.

http之server

http模块的设计充分利用了面向对象的继承多态,因为之前有看了会tfs文件系统的代码,所以再看python http时,没那么大的压力;先给出server的继承关系

 +------------------++------------+| tcpserver基类 || BaseServer +-------->| 开启事件循环监听 |+-----+------+ | 处理客户端请求 | | +------------------+ v +-----------------++------------+| httpserver基类 || TCPServer +-------->+设置监听socket |+-----+------+ | 开启监听 | | +-----------------+ v+------------+| HTTPServer | +------------+

立即学习“Python免费学习笔记(深入)”;

继承关系如上图所示,其中BaseServer和TCPServer在文件socketserver.py,HTTPServer在http/server.py;我们先看下来BaseServer;

BaseServer

因为BaseServer是所有server的基类,因此BaseServer尽可能抽象出所有server的共性,例如开启事件监听循环,这就是每个server的共性,因此这也是BaseServer主要做的使;我们来看下BaseServer主要代码部分

defserve_forever(self, poll_interval=0.5): self.__is_shut_down.clear()try:with_ServerSelector()asselector: selector.register(self, selectors.EVENT_READ)whilenotself.__shutdown_request: ready = selector.select(poll_interval)ifready: self._handle_request_noblock() self.service_actions()finally: self.__shutdown_request = False self.__is_shut_down.set()

立即学习“Python免费学习笔记(深入)”;

代码中的selector其实就是封装了select,poll,epoll等的io多路复用,然后将服务自身监听的socket注册到io多路复用,开启事件监听,当有客户端连接时,此时会调用self._handle_request_noblock()来处理请求;接下来看下这个处理函数做了啥;

def_handle_request_noblock(self):try: request, client_address = self.get_request()exceptOSError:returnifself.verify_request(request, client_address):try: self.process_request(request, client_address)except: self.handle_error(request, client_address) self.shutdown_request(request)else: self.shutdown_request(request)

立即学习“Python免费学习笔记(深入)”;

_handle_request_noblock函数是一个内部函数,首先是接收客户端连接请求,底层其实是封装了系统调用accept函数,然后验证请求,最后调用process_request来处理请求;其中get_request是属于子类的方法,因为tcp和udp接收客户端请求是不一样的(tcp有连接,udp无连接)

我们接下来再看下process_request具体做了什么;

defprocess_request(self, request, client_address): self.finish_request(request, client_address) self.shutdown_request(request)# -------------------------------------------------deffinish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self)defshutdown_request(self, request): self.close_request(request)

立即学习“Python免费学习笔记(深入)”;

process_request函数先是调用了finish_request来处理一个连接,处理结束之后,调用shutdown_request函数来关闭这个连接;而finish_request函数内部实例化了一个handler类,并把客户端的socket和地址传了进去,说明,handler类在初始化结束的时候,就完成了请求处理,这个等后续分析handler时再细看;