`

Tornado httpserver 源码简析

阅读更多
整个流程就是创建一个socket
  • socket.socket
  • socket.bind
  • socket.listen
  • socket.accept

一些值得注意的地方:
  • sock.setblocking
  • set_close_exec(sock.fileno())

#!/usr/bin/env python
#-*-encoding:utf-8-*-

from tornado import httpserver
from tornado import ioloop

def handle_request(request):
   message = "You requested %s\n" % request.uri
   request.write("HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s" % (
                 len(message), message))
   request.finish()
http_server = httpserver.HTTPServer(handle_request)#在此打断点,来看下httpserver运行的过程。
http_server.listen(8888)
ioloop.IOLoop.instance().start()


http_server = httpserver.HTTPServer(handle_request)
程序会进入HTTPServer的__init__方法中
self.request_callback = handle_request
然后
1、http_server = httpserver.HTTPServer(handle_request)
TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,
                           **kwargs)

跳转到TCPServer的__init__方法
self._sockets = {} # fd -> socket object此时fd还木有哦。
此处self._sockets声明为一个dict。
2、http_server.listen(8888)
此时调用TCPServer中的listen方法
    def listen(self, port, address=""):
        sockets = bind_sockets(port, address=address)
        self.add_sockets(sockets)

整个socket的处理被封装在一个netutil.py文件中
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                      0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)
        sockets.append(sock)
    return sockets


bind_sockets创建了一个socket
socket.socket(af, socktype, proto)
<socket object, fd=5, family=30, type=1, protocol=6>
等价于
socket.socket(socket.AF_INET,socket.SOCK_STREAM,IPPROTO_TCP)
fd即socketfd,由于UNIX套接字描述符也是文件描述符,所以统称fd.
接下来调用了
set_close_exec(sock.fileno())
这个方法定义在posix.py中
def set_close_exec(fd):
    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
    fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)


flags = fcntl.fcntl(fd, fcntl.F_GETFD)返回的flags为0;
fcntl.F_SETFD 对于fd设置文件描述符标志。此时FD_CLOEXEC = 1,即flags被置为1.
引用
F_GETFD 对应于fd的文件描述符标志作为函数值返回。当前只定义了一个文件描述符标志FD_CLOEXEC
FD_CLOEXEC用来设置文件的close-on-exec状态标准。在exec()调用后,close-on-exec标志为0的情况,此文件不被关闭。非零则在exec()后被关闭。默认close-on-exec状态为0,需要通过FD_CLOEXEC设置。

sock.setblocking(0)
引用
Set blocking or non-blocking mode of the socket: if flag is 0, the socket is set to non-blocking, else to blocking mode. Initially all sockets are in blocking mode. In non-blocking mode, if a recv() call doesn’t find any data, or if a send() call can’t immediately dispose of the data, a error exception is raised; in blocking mode, the calls block until they can proceed. s.setblocking(0) is equivalent to s.settimeout(0.0); s.setblocking(1) is equivalent to s.settimeout(None).

sock.bind(sockaddr)
sock.listen(backlog)
sockets.append(sock)
此时刚创建的socket加入到了sockets。
<socket object, fd=5, family=30, type=1, protocol=6>
<socket object, fd=6, family=2, type=1, protocol=6>
接着我们回到TCPServer中的
    def listen(self, port, address=""):
        sockets = bind_sockets(port, address=address)
        self.add_sockets(sockets)

    def add_sockets(self, sockets):
        if self.io_loop is None:
            self.io_loop = IOLoop.current()
        for sock in sockets:
            self._sockets[sock.fileno()] = sock#此处将sockets里面的socket转化为以sockfd为key socket为value 的字典。
            add_accept_handler(sock, self._handle_connection,
                               io_loop=self.io_loop)

def add_accept_handler(sock, callback, io_loop=None):

    if io_loop is None:
        io_loop = IOLoop.current()

    def accept_handler(fd, events):
        while True:
            try:
                connection, address = sock.accept()#用于接收client的connect
            except socket.error as e:
                if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
                    return
                raise
            callback(connection, address)
    io_loop.add_handler(sock.fileno(), accept_handler, IOLoop.READ)

本文涉及ioloop以及iostream的地方都未介绍。
下文会继续debug ioloop以及iostream的整个流程。
参考资料:
http://www.kegel.com/c10k.html
http://kenby.iteye.com/blog/1159621
http://docs.python.org/2/library/fcntl.html
http://docs.python.org/2/library/socket.html
分享到:
评论

相关推荐

    tornado-1.2.0源码

    Tornado的`httpserver`模块实现了HTTP服务器,`HTTPServer`类是核心,负责处理网络请求。它接收连接并创建`RequestHandler`实例来处理每个请求。`RequestHandler`处理HTTP请求,解析请求头,执行对应的处理方法,并...

    tornado框架短租web系统源码

    tornado作为用户产品后台服务器核心框架 redis 保存session数据、短时间房源信息、地域信息等,保存页面缓存数据,提高服务器响应速度 采用前后端完全分离架构,采用ajax异步调用、json数据传输,使后端接口可以...

    python+tornado开发的实例源码

    在"python+tornado开发的实例源码"中,我们可以学习到以下几个关键知识点: 1. **Python基础**:Python是一种高级编程语言,以其简洁明了的语法和丰富的标准库而闻名。在Tornado应用中,你需要了解Python的基本语法...

    Tornado源码分析之http服务器篇

    【标题】:“Tornado源码分析之http服务器篇” 这篇博客主要探讨了Tornado框架的HTTP服务器部分,Tornado是一个Python编写的异步网络库,它最初由FriendFeed团队开发,后来被Facebook收购并开源。Tornado因其高性能...

    Tornado WebServer

    1. **HTTPServer**:这是Tornado的基础,负责处理网络请求,与IOLoop(事件循环)紧密配合,处理异步请求。 2. **Application**:Tornado Application用于配置和组织路由,它可以关联多个URL路径到不同的请求处理...

    tornado源代码

    - **tornado**: 包含 Tornado 源码的核心模块,如 httpserver.py(HTTP 服务器实现)、websocket.py(WebSocket 支持)、ioloop.py(I/O 循环)等。 - **test**: 测试目录,包含了对 Tornado 各个组件的单元测试,...

    Tornado HTTP Server-开源

    Tornado HTTP Server是用Java编写的多线程Web服务器。 它旨在安全,高效和可移植,并提供HTTP 1.1的完整实现。 计划了高级功能,例如GZip输出压缩和基于Web的管理。

    tornado 2.2.2 source code

    《Tornado 2.2.2内核源码解析》 Tornado 2.2.2是VxWorks操作系统的一个重要版本,对于嵌入式开发人员来说,深入理解其内核源码对于优化系统性能、解决运行时问题以及进行定制化开发具有极大的价值。本文将对Tornado...

    tornado官方翻译文档

    6. HTTP服务器和客户端:tornado.httpserver和tornado.httpclient模块分别提供了非阻塞HTTP服务器和异步HTTP客户端的功能。 7. 本地化和国际化支持:tornado.locale模块支持应用的国际化。 8. WebSockets:tornado....

    tornado rpc

    from tornado.httpserver import HTTPServer application = Application([ (r"/jsonrpc", RPCService), (r"/xmlrpc", RPCService), ]) http_server = HTTPServer(application) http_server.listen(8888) IOLoop....

    tornado 4.0.1 python framework guide

    `tornado.httpserver` 模块提供了一个高性能的 HTTP 服务器实现。它能够处理大量的并发请求,并支持 HTTPS 加密通信。 **2.3 tornado.template — 灵活的输出生成** `tornado.template` 模块提供了一个简单但功能...

    股票分析系统源码,基于python,tornado框架.zip

    这个特定的源码是基于Python编程语言实现的,利用了Tornado框架,一个轻量级且高效的异步网络库。下面将详细介绍这个系统可能包含的关键知识点和相关技术。 首先,Python是当今最流行的编程语言之一,尤其在数据...

    Tornado 最新代码

    其次,Tornado提供了一个轻量级的HTTP服务器,名为Tornado HTTPServer,它与Web框架紧密集成,可以快速响应请求。此外,Tornado还包含一个模板引擎(Tornado Templates),用于生成动态HTML页面。它支持嵌入式Python...

    Tornado实现多进程/多线程的HTTP服务详解

    用tornado web服务的基本流程 1.实现处理请求的Handler,该类继承自tornado.web.RequestHandler,实现用于处理请求的...3.初始化一个tornado.httpserver.HTTPServer对象,构造函数的参数是上一步的Application对象。

    基于tornado的BBS问答社区源码.rar

    基于tornado的BBS问答社区源码 计算机语言:python 授权模块: * 登陆 * 注册 * 注销 * 验证码 问题模块: * 问题列表 * 问题分页 * 问题创建 * 问题上传图片 * 问题删除 * 问题详情 * 问题搜索 * 问题过滤 [最新...

    tcp_server_honorus2_pythonTCP_tcp_tornado_pythonserver_

    标题中的"tcp_server_honorus2_pythonTCP_tcp_tornado_pythonserver_"表明这是一个关于使用Python的Tornado框架构建TCP服务器的项目。Tornado是一个强大的、异步的网络库,特别适合处理高并发的TCP连接,常用于实时...

    Python高效开发实战 Django Tornado Flask Twisted

    Tornado的内建HTTP服务器使其易于部署,并且它还支持非阻塞HTTP客户端。Tornado还提供了模板引擎以及对C扩展的支持。 Flask是一个用Python编写的轻量级Web应用框架,它的设计理念是简单、灵活、可扩展。与Django...

    HTTP请求定时任务自动执行框架 base on HAR Editor and Tornado Server.zip

    【HTTP请求定时任务自动执行框架】是用于自动化执行HTTP请求的一种解决方案,该框架基于HAR Editor和Tornado Server构建。HAR(HTTP Archive)是一种JSON格式的文件,用于记录浏览器与服务器之间的HTTP交互数据,...

    源码:zk-SNARKs实战:使用circom和snarkjs实现简单版的Tornado

    该源代码对应本人博文《zk-SNARKs实战:使用circom和snarkjs实现简单版的Tornado(含源码)》,如要看该文章,可直接在百度中根据题目搜索

    tornado python web开发

    Tornado全称Tornado Web Server,是一个用Python语 言写成的Web服 务器兼Web应用框架,由FriendFeed公 司 在自己的网站FriendFeed中使用,被Facebook收购 以后框架在2009年9月以开源软件形式开放给大众。 特点: 作为...

Global site tag (gtag.js) - Google Analytics