Chinaunix首页 | 论坛 | 博客
  • 博客访问: 480859
  • 博文数量: 111
  • 博客积分: 2332
  • 博客等级: 大尉
  • 技术积分: 1187
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-29 11:22
文章分类

全部博文(111)

文章存档

2013年(9)

2012年(28)

2011年(17)

2010年(28)

2009年(29)

我的朋友

分类: Python/Ruby

2012-04-20 16:21:08

今天做c语言发送http请求测试,自己写的http协议的报文总是不能被tornado识别,但是apache和nginx就没问题,所以就看了看tornado的代码。
 
先看一段torando的示例程序
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()

可以看出tornado运行其实是分为两段的。一段是application,是关于应用的。一段是ioloop是关于网络io的。
首先看一下应用这一段。跟踪一下application.listen(8000)这行代码。
web.py的1176行有对Application类的listen函数的定义。在这里面调用了HTTPServer类的listen函数。
HTTPServer定义在httpserver.py,他继承自TCPServer,然后没对listen函数做操作。所以Application其实是直接调用的TCPServer的listen函数。
netutil.py的92行TCPServer的listen调用了bind_sockets。参数是port(8000,传进来的)和address("",默认的)。
netutil.py的220行,定义了bind_sockets。他调用了getaddrinfo得到了本地建立socket的一些信息。包括socket通信域、socket类型、socket协议等等。然后建立socket,并且把这个socket返回。其实在这个时候,服务器端的网络监听已经建立完成了。
然后回到netutil.py92行的listen函数里。在这里调用了add_sockets,并且将刚才返回的额socket传给了他。在add_sockets里面首先会生成一个ioloop对象,又调用了add_accept_handler,并且把这个ioloop对象和TCPServer的_handle_connection函数作为call_back传给了它。在add_accept_handler里面,调用之前生成的ioloop对象的add_handler函数,这次加的handler相当于是 加上了对数据的接收,在这里面调用了socket.accept。

然后再看 tornado.ioloop.IOLoop.instance().start()这一行代码
在这里tornado.ioloop.IOLoop.instance()得到的就是之前一行代码里声称的ioloop对象
ioloop.py的230行左右有对start函数定义。当有请求来的时候,epoll会往下走。在start函数的最后有self._handlers[fd](fd, events),其实就是调用了前面分析的_handle_connection这个call_back。
_handle_connection会调用handle_stream来处理来的请求内容。因为HTTPServer类继承自TCPServer类,并且改写了handler_stream函数,所以调用的其实是HTTPServer类的handler_stream(之前调用的也都是HTTPServer类的,只不过 HTTPServer的函数都是继承下来的,所有都是在其他类的代码文件里面看的代码)。
在HTTPServer类的handler_stream里面,生成了一个HTTPConnection对象。
在HTTPConnection类的构造函数里面,有self.stream.read_until(b("\r\n\r\n"), self._header_callback)。说明tornado解析http格式的报文,只能解析报文头以\r\n\r\n结束的,不能解析以\n\n结束的。并且调用_head_callback来解析http报头
在HTTPConnection类的构造函数里面,有self._header_callback = stack_context.wrap(self._on_headers)。
在_on_headers函数是解析http协议头的各个字段的。在这里面有eol = data.find("\r\n")。说明tornado解析http格式报文头的各个字段,只能解析以\r\n分隔的,不能解析以\n分隔的。



阅读(1513) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

背包包1112012-04-23 21:12:37

多写类似的笔记很有好处啊~