• TrafficServer http2 代码分析


    TrafficServer 是Apache基金会的 HTTP/HTTP2 代理服务器。

    TrafficServer 的 HTTP2 部分主要的代码在 :

    1. trafficserver/proxy/http2/HTTP2.h, HTTP2.cc
    2. trafficserver/proxy/http2/Http2Stream.h, Http2Stream.cc
    3. trafficserver/proxy/http2/Http2ClientSession.h, Http2ClientSession.cc
    4. trafficserver/proxy/http2/Http2ConnectionState.h, Http2ConnectionState.cc
    5. trafficserver/proxy/http2/ Http2DependencyTree.h, Http2DependencyTree.cc
    6. trafficserver/proxy/http2/HPACK.h, HPACK.cc
    7. trafficserver/proxy/http2/HuffmanCodec.h, HuffmanCodec.cc

    1. trafficserver/proxy/http2/HTTP2.h, HTTP2.cc

    10种Frame 的struct定义,解析/序列化函数,HeaderList转换函数,一些常量定义

    2. trafficserver/proxy/http2/Http2ClientSession.h, Http2ClientSession.cc

    Http2ClientSession 处理 io event 事件,解析 FrameHeader,

    调用顺序:

    Http2ClientSession::main_event_handler()
    
    --> state_read_connection_preface()
    
    --> state_start_frame_read()
    
    --> state_process_frame_read() 解析出一个完整的Frame
    
    --> do_complete_frame_read()
    
    --> Http2ConnectionState::main_event_handler(HTTP2_SESSION_EVENT_RECV )
    
    

    3. trafficserver/proxy/http2/Http2ConnectionState.h, Http2ConnectionState.cc

    Http2ConnectionState,对应一个 HTTP2 连接,代码基本等价于 proxygen 的 HTTPSession,主要的成员变量:

    {     
        双链表<Http2Stream> //略挫,有个find_stream 用的遍历,改map好点。
    
        Http2ClientSession,
    
        HpackHandle 2个,
    
        DependencyTree,
    
        Http2ConnectionSettingsclient_settings server_settings,连接的几个 Settings 配置项,一个int数组
    }
    

    主要的方法:各个 rcv_xxx_frame() 和 send_xxx_frame(0
    Http2ConnectionState::main_event_handler(HTTP2_SESSION_EVENT_RECV )里面,解析输入的各种 Frame

    • rcv_data_frame, // HTTP2_FRAME_TYPE_DATA
    • rcv_headers_frame, // HTTP2_FRAME_TYPE_HEADERS
    • rcv_priority_frame, // HTTP2_FRAME_TYPE_PRIORITY
    • rcv_rst_stream_frame, // HTTP2_FRAME_TYPE_RST_STREAM
    • rcv_settings_frame, // HTTP2_FRAME_TYPE_SETTINGS
    • rcv_push_promise_frame, // HTTP2_FRAME_TYPE_PUSH_PROMISE
    • rcv_ping_frame, // HTTP2_FRAME_TYPE_PING
    • rcv_goaway_frame, // HTTP2_FRAME_TYPE_GOAWAY
    • rcv_window_update_frame, // HTTP2_FRAME_TYPE_WINDOW_UPDATE
    • rcv_continuation_frame, // HTTP2_FRAME_TYPE_CONTINUATION

    还有发送各类 frame 的接口,send_data_frames()/send_headers_frame() / send_push_promise_frame() / send_rst_stream_frame() 等。

    具体地:

    rcv_data_frame :

    find_stream,然后检查stream的state是不是OPEN/HALF_CLOSE_LOCAL,去除 padding,处理END_STREAM flag,检查本端流量控制 window_size ,保存buffer,更新本地的window,发回 Connection 和 Stream Level 的WindowUpdate Frame。

    rcv_headers_frame:

    find_stream/create_stream,处理padding,处理PRIORITY flag添加到 PriorityTree 里面,如果 Header Block 结束了(即有END_HEADERS FLAG),那就http2_decode_header_blocks() 做HPACK 解压缩,调用 Http2Stream 处理解析出的HeaderList

    rcv_priority_frame:

    find_stream,reprioritize,重新调整树。

    rcv_rst_stream_frame

    rcv_settings_frame:

    parse检查收到的各个配置项,更新到client_settings中,并发送SETTINGS_ACK

    rcv_push_promise_frame 等

    包括 rcv_ping_frame

    rcv_goaway_frame:

    rcv_window_update_frame

    比较简单,略。

    rcv_continuation_frame

    类似 rcv_headers_frame

    send_data_frames_depends_on_priority

    取了 DependencyTree的top(),

    send_data_frames 等

    send_a_data_frame

    send_headers_frame

    send_push_promise_frame

    send_rst_stream_frame

    send_settings_frame

    send_ping_frame

    send_goaway_frame

    send_window_update_frame

    比较简单,就是检查字段合法性,序列化,然后发送。

    4. trafficserver/proxy/http2/Http2Stream.h, Http2Stream.cc

    对应实现HTTP2 的Stream,重要的成员变量有:

    Http2StreamState _state;//实现IDLE,OPEN,RESERVED,HALF_CLOSE等的切换。

    DependencyTree::Node *priority_node;// Priority Tree中的节点指针。

    5. trafficserver/proxy/http2/Http2DependencyTree.h, Http2DependencyTree.cc

    Http2DependencyTree::Node 表示一个Stream,成员变量有:

    {
     bool actived;  //是否有输出数据
     bool queued; //是否在 actived 队列中
     uint32_t id;
     uint32_t weight;
     uint32_t point;   //queue中的节点按照这个 point 做优先级排序
     Node *parent;  //父节点
     DLL<Node> children; //子节点的双列表
     
     PriorityQueueEntry<Node *> *entry; // 
     PriorityQueue<Node *> *queue;   //有输出数据的所有子节点的队列,按point 优先级降序排列
    
     Http2Stream *t;
    }
    

    Http2DependencyTree 中有个 Node * root 指向 树的根节点。

    Http2DependencyTree的主要方法有:

    1. Node *find(uint32_t id);
      DFS 递归遍历树,查找一个Stream。

    2. Node *add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T t);
      就是插入 parent 的 children 链表中,兼做 exclusive 处理。

    3. void remove(Node *node);
      从parent 的 queue 中移除自己,把自己的 queue 全转给 parent,把自己的 children 全转给 parent

    4. void reprioritize(uint32_t new_parent_id, uint32_t id, bool exclusive);
      重排优先级,就是移动节点

    5. Node *top();
      返回整个树中,point 最高的叶子节点。递归实现。

    6. void activate(Node *node);
      往上遍历,如果当前节点没有 在 parent 的 queue中,加入

    7. void deactivate(Node *node, uint32_t sent);
      从parent 的queue中去除自己。

    8. void update(Node *node, uint32_t sent);

    这里使用 Weighted Fair Queue (WFQ) Scheduling 来调度 Stream 之间的优先级。

    Http2ConnectionState::send_data_frames_depends_on_priority()
    中,是直接取了 树的 top() 节点,

    6. trafficserver/proxy/http2/HPACK.h, HPACK.cc

    实现 HPACK 压缩/解压缩

    7. trafficserver/proxy/http2/HuffmanCodec.h, HuffmanCodec.cc

    实现静态的 Huffman 表,接口简单,只有4个函数,,

    是实现成 二叉树,相比proxygen估计效率会低一些。

  • 相关阅读:
    学习方式的反省
    我又辞职了!
    mysql完全备份,增量备份及恢复脚本
    marquee.js jQuery 多功能无缝滚动插件
    ul与li应用样式及其兼容性
    闲谈 JavaScript 之事件绑定(转载自万戈)
    JavaScript 中万变不离其宗的 this 应用场景
    ScrollUp – 超轻量的可定制的回到顶部 jQuery 插件
    jQuery之Tab切换代码改进
    jQuery Unveil – 另一款非常轻量的延迟加载插件
  • 原文地址:https://www.cnblogs.com/windydays/p/12810658.html
Copyright © 2020-2023  润新知