python自带的http模块详解
|
挺久没写博客了,因为博主开始了今年另一段美好的实习经历,学习加做项目,时间已排满;很感谢今年这两段经历,让我接触了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 sys
from http.server import HTTPServer,SimpleHTTPRequestHandler
ServerClass = HTTPServer
HandlerClass = SimpleHTTPRequestHandler
if__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("nKeyboard interrupt received,exiting.")
httpd.server_close()
sys.exit(0)
运行上述例子,可以得到如下: python3 myhttp.py 127.0.0.1 9999 此时如果在当前文件夹新建一个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 | +------------+ 继承关系如上图所示,其中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() 代码中的selector其实就是封装了select,poll,epoll等的io多路复用,然后将服务自身监听的socket注册到io多路复用,开启事件监听,当有客户端连接时,此时会调用self._handle_request_noblock()来处理请求;接下来看下这个处理函数做了啥; def_handle_request_noblock(self): try: request,client_address = self.get_request() exceptOSError: return ifself.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) _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,client_address): self.RequestHandlerClass(request,client_address,self) defshutdown_request(self,request): self.close_request(request) process_request函数先是调用了finish_request来处理一个连接,处理结束之后,调用shutdown_request函数来关闭这个连接;而finish_request函数内部实例化了一个handler类,并把客户端的socket和地址传了进去,说明,handler类在初始化结束的时候,就完成了请求处理,这个等后续分析handler时再细看; 以上就是BaseServer所做的事,这个BaseServer不能直接使用,因为有些函数还没实现,只是作为tcp/udp的抽象层;总结下: 先是调用serve_forever开启事件监听; TCPServer 由上述BaseServer抽象出的功能,我们可以知道TCPServer或UDPServer应该完成的功能有,初始化监听套接字,并绑定监听,最后当有客户端请求时,接收这个客户端;我们来看下代码 BaseServer==> 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() self.__shutdown_request = False #-------------------------------------------------------------------------------- TCPServer==> def__init__(self,RequestHandlerClass,bind_and_activate=True): BaseServer.__init__(self,RequestHandlerClass) self.socket = socket.socket(self.address_family,self.socket_type) ifbind_and_activate: try: self.server_bind() self.server_activate() except: self.server_close() raise TCPServer初始化时先是调用基类BaseServer的初始化函数,初始化服务器地址,handler类等,然后初始化自身的监听套接字,最后调用server_bind绑定套接字,server_activate监听套接字 defserver_bind(self): ifself.allow_reuse_address: self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) self.socket.bind(self.server_address) self.server_address = self.socket.getsockname() defserver_activate(self): self.socket.listen(self.request_queue_size) TCPServer还实现了另一个函数,那就是接收客户端请求, defget_request(self): returnself.socket.accept() 之前如果有学过linux编程,那么看这些代码应该会觉得很熟悉,因为函数名和Linux提供的系统调用名一模一样,这里也不多说了; TCPServer其实已经把基于tcp的服务器主体框架搭起来了,因此HTTPServer在继承TCPServer基础上,只是重载了server_bind函数,设置reuse_address等; ok,这里分析下上述例子程序的开启过程; httpd = ServerClass(server_address,HandlerClass)这行代码在初始化HTTPServer时,主要是调用基类TCPServer的初始化方法,初始化了监听的套接字,并绑定和监听; http之handler handler类主要分析tcp层的handler和http应用层的handler,tcp层的handler是不能使用的,因为tcp层只负责传输字节,但是并不知对于接收到的字节要如何解析,如何处理等;因此应用层协议如该要使用TCP协议,必须继承TCP handler,然后实现handle函数即可;例如,http层的handler实现handle函数,解析http协议,处理业务请求以及结果返回给客户端;先来看下tcp层的handler tcp层handler tcp层handler主要有BaseRequestHandler和StreamRequestHandler(都在socketserver.py文件),先看下BaseRequestHandler代码, classBaseRequestHandler: def__init__(self,server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish() defsetup(self): pass defhandle(self): pass deffinish(self): pass 之前在看server时,知道处理客户端请求就是在handler类的初始化函数中完成;由这个基类初始化函数,我们知道处理请求大概经历三个过程:
(编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
