Skip to content

Instantly share code, notes, and snippets.

@polebug
Created November 7, 2017 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save polebug/6602879109d7a96c5d2a7612946ff490 to your computer and use it in GitHub Desktop.
Save polebug/6602879109d7a96c5d2a7612946ff490 to your computer and use it in GitHub Desktop.
WSGI 协议实现与 Python socket 编程补充说明

偶然看到有人翻译的“一起写一个 web 服务器”系列[1][2][3],感觉挺不错的,这里做一些归纳和 Python socket 编程的补充说明。

WSGI 的工作原理

常见的 Web server 无法与 Web application(Flask, Django, Tornado) 直接通信,需要 WSGI server 作为桥梁。

WSGI 工作原理分为两方面

服务器层: 将来自 socket 的数据包解析为 http,调用 application,给应用提供环境信息 environ (包含 host, post, process模式, 客户端的 header, body 等)。同时给应用提供一个 start_response 的回调函数,主要在应用程序层进行响应信息处理。

应用程序层: 在 server 提供的 start_response 生成 header, body, status,将这些信息返回给客户端。

WSGI server 代码结构

这部分我想根据 Web 服务器处理发给应用的请求的流程,来说说完整的 server 代码结构:
  • 首先,服务器启动并加载一个由 Web 框架/应用提供的 application - def set_app()
  • 启动 WSGI server 服务,不停监听并获取 socket 数据 - def serve_forever
  • 处理请求:def handle_one_request()   - 对 socket 数据包进行解析 def parse_request()   - 创建 environ 字典,提供环境信息 def get_environ()   - 提供 start_response 回调函数 def start_response()   - 使用 environ 和 start_response 作为参数调用 application,并拿到返回的响应体   - 解析一次请求后,关闭 socket 端口,同时将 application 返回的数据返回至客户端 def finish_response()
  • 完整服务器代码

    WSGI app 代码结构

    简单的说就是设置 status, header 等,通过 start_response 传给服务器,构造 http 响应

    代码比较简单:

    def app(environ, start_response):
        status = '200 OK'
        response_headers = [('Content-Type', 'text/plain')]
        start_response(status, response_headers)
        return ['Hello world from a simple WSGI application!\n']

    补充:Python socket 编程

    这里主要是对 WSGI_server 中所用的的 socket 模块进行补充

    Socket 模块提供了标准的 BSD Socket API

    Socket 类型

    套接字格式:socket(family, type[,protocal]) 使用给定的套接族,套接字类型,协议编号(默认为0)来创建套接字

    socket.AF_INET - 用于服务器与服务器之间的网络通信

    socket.SOCK_STREAM - 基于 TCP 的流式 socket 通信

    创建 TCP Socket:

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    

    Socket 函数

    #服务端 Socket 函数

    s.listen(backlog) - 开始监听TCP传入连接,backlog指定在拒绝链接前,操作系统可以挂起的最大连接数,该值最少为1,大部分应用程序设为5就够用了

    s.bind(address) - 将套接字绑定到地址,在AF_INET下,以tuple(host, port)的方式传入

    #公共 Socket 函数

    s.getsockname() - 返回套接字自己的地址,返回值通常是一个tuple(ipaddr, port)

    s.setsockopt(level,optname,value) - 设置给定套接字选项的值。level 定义了哪个选项将被使用,通常情况下是 SOL_SOCKET。

    s.getfqdn - 返回一个name对应的完全合格的域名。如果name被忽略,将会被解释为本地主机。


    可能将持续补充

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment