Rust in Everything
基于 hyper 1.12.0

运行时抽象与核心类型

hyper 的两条主线一头是字节流,一头是 Request / Response。这一部分讲两头分别长什么样:字节流在 hyper 眼里是什么 trait,hyper 需要后台任务和计时器时找谁要,你写的处理逻辑以什么 trait 交给 hyper,body 又是什么。这些东西 hyper 自己只定义接口,tokio 上的实现都在 hyper-util 的 rt::tokio 和 service 两个模块里。

  1. IO trait:hyper::rt::Read / Write 和 tokio 的 AsyncRead / AsyncWrite 几乎一样,但 hyper 要自己拥有它们,为将来的完成式 IO(io-uring)留位置。ReadBuf / ReadBufCursor 让读操作直接写进未初始化的内存。TokioIo 两个方向都能转。
  2. Executor 与 Timer:Executor 只有一个 execute,只有 HTTP/2 用它;Timer 给出 Sleep。没有 timer 时 hyper 怎么办分三种:now() 退回 Instant::now(),默认的 header_read_timeout 静默失效,显式配置的超时和 HTTP/2 keep-alive 则 panic。
  3. Service 与 Body:hyper 的 Service 只有 call(&self),没有 poll_ready;HttpService 是它在 HTTP 上的封闭别名。tower 服务经 TowerToHyperService 接入,每个请求克隆一次。Body::poll_frame 一次给一帧,is_end_stream 和 size_hint 决定响应怎么分帧。
  4. 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。

💬 关联讨论

发起讨论
加载中...