运行时抽象与核心类型
hyper 的两条主线一头是字节流,一头是 Request / Response。这一部分讲两头分别长什么样:字节流在 hyper 眼里是什么 trait,hyper 需要后台任务和计时器时找谁要,你写的处理逻辑以什么 trait 交给 hyper,body 又是什么。这些东西 hyper 自己只定义接口,tokio 上的实现都在 hyper-util 的 rt::tokio 和 service 两个模块里。
- IO trait:
hyper::rt::Read/Write和 tokio 的AsyncRead/AsyncWrite几乎一样,但 hyper 要自己拥有它们,为将来的完成式 IO(io-uring)留位置。ReadBuf/ReadBufCursor让读操作直接写进未初始化的内存。TokioIo两个方向都能转。 - Executor 与 Timer:
Executor只有一个execute,只有 HTTP/2 用它;Timer给出Sleep。没有 timer 时 hyper 怎么办分三种:now()退回Instant::now(),默认的header_read_timeout静默失效,显式配置的超时和 HTTP/2 keep-alive 则 panic。 - Service 与 Body:hyper 的
Service只有call(&self),没有poll_ready;HttpService是它在 HTTP 上的封闭别名。tower 服务经TowerToHyperService接入,每个请求克隆一次。Body::poll_frame一次给一帧,is_end_stream和size_hint决定响应怎么分帧。 - rt::tracing:hyper-util 0.1.21 起
TokioExecutor不再把当前 tracing span 传给 spawn 的任务,改由CurrentSpanExecutor、WithSpanExecutor、MkSpanExecutor三个包装器按需选择;传播 span 时,请求的 span 要等连接任务和池的清理任务结束才关闭。
flowchart TB tcp["tokio TcpStream"] -->|TokioIo| io["rt::Read + rt::Write"] io --> conn["serve_connection"] exec["TokioExecutor"] -->|"Executor(仅 HTTP/2)"| conn timer["TokioTimer"] -->|Timer| conn tr["CurrentSpanExecutor 等"] -->|包住| exec tower["tower Service"] -->|TowerToHyperService| svc["hyper Service"] svc --> conn conn --> body["Request 带 Incoming"] svc --> resp["Response 带 impl Body"]
左边一列都是 tokio / tower 的类型,中间一列是 hyper 认识的 trait,箭头上的名字是 hyper-util 提供的适配器。serve_connection 本身见 服务端 Builder 与 Connection。
💬 关联讨论
发起讨论加载中...