HTTP/1 连接
这是本卷的重点。http1::Builder::serve_connection 返回一个 future,一条连接上的所有请求都在这个 future 里处理,不另开任务。读懂这一部分,就读懂了服务端主线的大半;客户端主线用的也是同一套代码,只换了两个 trait 的实现(Dispatch 和 Http1Transaction)。
七章按「从外到内」排列:先是对外的 builder,然后是驱动一切的循环和它依赖的状态机,再往下是消息头、body、缓冲区三层,最后是离开 HTTP 的那条路。
- 服务端 Builder 与 Connection:
http1::Builder的选项和默认值(keep-alive 开、header_read_timeout默认 30 秒、自动加Date、half_close关),serve_connection把它们写进Conn、包成Connectionfuture;graceful_shutdown、without_shutdown/into_parts、with_upgrades都在这一层。 - Dispatcher:
poll_loop每次最多转 16 圈,每圈读、写、刷新各一次,转满就唤醒自己再让出。Dispatch的服务端实现调服务、存in_flight;同一条连接上的请求严格串行,pipelining 只省往返。 - Conn 的读写状态机:
Reading、Writing两个枚举加一个KA,读写都到KeepAlive且KA是Busy才一起回到Init;Connection: close、HTTP/1.0、Expect: 100-continue、对端半关闭都落在这几个状态上。 - 解析与编码:
role.rs的Server和Client用 httparse 解析消息头、定出 body 长度,解析失败自动回 400 / 414 / 431;编码时选Content-Length还是 chunked,补上缓存的Date。 - body 的解码与编码:
Decoder的Length、Chunked、Eof三种,chunked 是逐字节的状态机;Encoder的Length、Chunked、CloseDelimited三种。 - 读写缓冲:
Buffered的读缓冲从 8 KiB 起按读到的量伸缩,上限是max_buf_size;写缓冲在 IO 支持向量写时用Queue,否则用Flatten拷进一块连续内存。 - 协议升级:
Upgrade头或CONNECT让请求带上OnUpgrade;101写完后Dispatcher返回Upgrade,with_upgrades把 IO 和多读的字节合成Upgraded交出去。
flowchart TB builder["Builder 与 Connection"] --> disp["Dispatcher:poll_loop"] disp --> dispatch["Dispatch:Server 或 Client"] disp --> conn["Conn:读写状态机"] conn --> role["role:解析与编码消息头"] conn --> codec["Decoder 与 Encoder"] conn --> buffered["Buffered:读写缓冲"] buffered --> io["rt::Read + rt::Write"] disp --> upg["Upgrade:交出 IO"]
Dispatcher 只知道「该推哪一边」,Conn 只知道「哪一边能推」,字节格式全在 role、Decoder、Encoder 里,缓冲区是最底下一层。读的时候可以先读 2、3 两章搭起骨架,再按需下钻。
💬 关联讨论
发起讨论加载中...