Skip to content

workbunny/http2-protocol

Repository files navigation

HTTP/2 Protocol

基于 Workerman 的 HTTP/2 协议实现 (RFC 7540 / RFC 7541)

提供完整的 HTTP/2 帧解析、HPACK 头部压缩、流多路复用和流控能力, 通过 Workerman 的 ProtocolInterface 透明接入,Server/Client 均可使用。

环境要求

安装

composer require workbunny/http2-protocol

架构

TCP 字节流
    │
    ▼
┌─────────────────────────┐
│  Protocols\Http2         │  Workerman ProtocolInterface
│  input() / decode()     │
│  / encode()             │
└───────┬─────────────────┘
        │
        ▼
┌─────────────────────────┐
│  Frame                  │  RFC 7540 Section 4-6
│  DATA / HEADERS /       │
│  SETTINGS / PING / ...  │
└───────┬─────────────────┘
        │
        ▼
┌─────────────────────────┐
│ Stream                  │  流管理、多路复用、流控
│ Request / Response      │
└───────┬─────────────────┘
        │
        ▼
┌─────────────────────────┐
│  HPack                  │  RFC 7541 头部压缩
│  Encoder / Decoder      │  静态表 + 动态表 + Huffman
│  StaticTable /          │
│  DynamicTable           │
└─────────────────────────┘

数据流

收: TCP → input(帧完整性) → decode(帧解析+路由) → Frame → handler → HPack 解码 → onMessage
发: onMessage → 业务数组 → encode(编码) → Frame → HPack 编码 → TCP

快速开始

Server 端

use Protocols\Http2;
use Workerman\Worker;

$worker = new Worker('http2://0.0.0.0:8080');

$worker->onConnect = function ($connection) {
    Http2::initConnection($connection);
};

$worker->onClose = function ($connection) {
    Http2::destroyConnection($connection);
};

$worker->onMessage = function ($connection, $request) {
    // $request = [
    //     'stream_id' => int,
    //     'stream'    => Stream,
    //     'headers'   => list<array{string, string}>,
    //     'body'      => string,
    // ]
    $streamId = $request['stream_id'];

    $connection->send([
        'stream_id' => $streamId,
        ':status'   => '200',
        'headers'   => ['content-type' => 'text/plain'],
        'body'      => 'Hello HTTP/2!',
    ]);
};

Worker::runAll();

测试:

php server.php start
curl --http2-prior-knowledge -v http://127.0.0.1:8080/

Client 端

use Protocols\Http2;
use Workerman\Connection\AsyncTcpConnection;
use Workerman\Worker;

$worker = new Worker();
$worker->onWorkerStart = function () {
    $conn = new AsyncTcpConnection('http2://127.0.0.1:8080');

    $conn->onConnect = function ($conn) {
        Http2::initConnection($conn);

        // 发送请求,stream_id 自动分配(1, 3, 5, ...)
        $conn->send([
            ':method'   => 'GET',
            ':path'     => '/',
            ':scheme'   => 'http',
            ':authority'=> '127.0.0.1:8080',
        ]);
    };

    $conn->onMessage = function ($conn, $data) {
        if ($data === null) return;
        echo $data['body'];
    };

    $conn->onClose = function ($conn) {
        Http2::destroyConnection($conn);
    };

    $conn->connect();
};

Worker::runAll();

完整示例见 examples/

目录结构

.
├── src/
│   ├── Protocol/Http2.php       # Workerman 协议入口 (input/decode/encode)
│   ├── Constants.php            # RFC 7540 常量定义
│   ├── Stream.php               # 流管理、多路复用、流控
│   ├── Frame/
│   │   ├── AbstractFrame.php    # 帧基类 (解析/编码/handler)
│   │   ├── DataFrame.php        # DATA 帧
│   │   ├── HeadersFrame.php     # HEADERS 帧
│   │   ├── PriorityFrame.php    # PRIORITY 帧
│   │   ├── RstStreamFrame.php   # RST_STREAM 帧
│   │   ├── SettingsFrame.php    # SETTINGS 帧
│   │   ├── PushPromiseFrame.php # PUSH_PROMISE 帧
│   │   ├── PingFrame.php        # PING 帧
│   │   ├── GoawayFrame.php      # GOAWAY 帧
│   │   ├── WindowUpdateFrame.php# WINDOW_UPDATE 帧
│   │   └── ContinuationFrame.php# CONTINUATION 帧
│   └── HPack/
│       ├── StaticTable.php      # 静态表 (RFC 7541 Appendix A)
│       ├── DynamicTable.php     # 动态表
│       ├── IntegerCodec.php     # N-bit prefix 整数编解码
│       ├── Huffman.php          # 哈夫曼编解码 (RFC 7541 Appendix B)
│       ├── Encoder.php          # HPACK 编码器
│       └── Decoder.php          # HPACK 解码器
├── examples/
│   ├── http2-server.php         # Server 示例
│   └── http2-client.php         # Client 示例
├── tests/
│   └── HPack/                   # HPack 单元测试
└── vendor/

核心概念

input / decode / encode

遵循 Workerman ProtocolInterface

方法 职责 输入 → 输出
input() 判定帧完整性 stringint(帧长度)
decode() 解析帧 → handler 路由 stringarray|null
encode() 编码为二进制帧 Frame|array|stringstring

连接管理

// onConnect 中初始化
Http2::initConnection($connection);

// 优雅关闭(发送 GOAWAY 帧后关闭连接)
Http2::shutdown($connection);
$connection->close();

// onClose 中清理
Http2::destroyConnection($connection);

请求/响应格式

Server 收到的请求 (decode() 返回):

[
    'stream_id' => 1,
    'stream'    => Stream,           // Stream 实例
    'headers'   => [                 // HPack 解码后的头部列表
        [':method', 'GET'],
        [':path', '/'],
        [':scheme', 'http'],
        [':authority', 'example.com'],
        ['user-agent', 'curl/8.0'],
    ],
    'body'      => '',               // 请求体
]

Server 发送的响应 (encode() 接受):

[
    'stream_id' => 1,
    ':status'   => '200',           // 或 'status' => 200
    'headers'   => [                // 可选,自定义响应头
        'content-type' => 'text/html',
    ],
    'body'      => '<h1>OK</h1>',   // 可选
]

Client 发送的请求 (encode() 接受):

[
    'stream_id' => 1,
    ':method'   => 'GET',
    ':path'     => '/api/users',
    ':scheme'   => 'https',
    ':authority'=> 'example.com',
    'headers'   => [                // 可选,自定义请求头
        'accept' => 'application/json',
    ],
    'body'      => '',              // 可选
]

encode() 自动判断:有 :method → 按请求编码,有 :status → 按响应编码。

Frame 帧

所有帧类型继承 AbstractFrame,统一提供:

  • parse(buffer) — 静态工厂,根据 buffer 中 type 字段自动分发到对应子类
  • validate(buffer) — 验证帧合法性
  • encode() — 编码为二进制
  • handler(stream, connection) — 帧到达时的处理逻辑

Stream 流

  • 状态机:IDLE → OPEN → HALF_CLOSED → CLOSED
  • 每个 Stream 独立持有 HPack 编解码器(共享动态表)
  • 支持流级别流控窗口(自动 WINDOW_UPDATE)
  • 连接通过 $connection->streamPool 持有 Stream 池

开发

运行单元测试

composer install --dev
./vendor/bin/phpunit

启动示例 Server

php examples/http2-server.php start

代码格式化

composer fmt

待完善

当前无已知待完善项。如需扩展可参考:

方向 说明
流式发送大 body encodeResponse() 一次性编码 HEADERS + DATA,超大 body 可改为分片发送
Client 端协议封装 当前 Client 需手动处理 PREFACE + SETTINGS 交换,可封装 Http2Client

License

Apache-2.0

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages