跳到正文
Yayin Story Studio Yayin Story Studio 项目文档

Visindigo::Network::IStreamDecoder Class

class Visindigo::Network::IStreamDecoder

流帧解码器接口. 详情...

头文件: #include <Network/HttpTypes.h>
自以下版本: Visindigo 0.17.0
被继承:

Visindigo::Network::JsonLinesDecoder and Visindigo::Network::SseDecoder

公开成员函数

(自 Visindigo 0.17.0 引入) virtual ~IStreamDecoder()
(自 Visindigo 0.17.0 引入) virtual QList<Visindigo::Network::StreamFrame> feed(const QByteArray &chunk) = 0
(自 Visindigo 0.17.0 引入) virtual QList<Visindigo::Network::StreamFrame> finish() = 0
(自 Visindigo 0.17.0 引入) virtual qint64 getBufferedBytes() const = 0
(自 Visindigo 0.17.0 引入) virtual qint64 getMaxFrameBytes() const = 0
(自 Visindigo 0.17.0 引入) virtual void reset() = 0
(自 Visindigo 0.17.0 引入) virtual void setMaxFrameBytes(qint64 bytes) = 0

详细说明

IStreamDecoder 把"持续到达的字节流"切成一个个完整的 Visindigo::Network::StreamFrame。 请求中心只依赖本接口,对具体文本格式(SSE、NDJSON,或调用方自定义的格式) 保持中立:新增一种流格式只需要实现本接口,中心与句柄都不必改动。

实现本接口时必须满足以下约定,否则会在真实网络环境中出错:

  • 必须能处理任意切分点。TCP 是字节流协议,分包边界与帧边界毫无关系, 一个帧可能被拆到任意多次 feed() 中到达,也可能一次到达包含多个帧。 实现必须自行缓存不完整的尾部,而不能假设"每次调用恰好是一个完整帧"。
  • 状态必须可重置。请求因重试或重定向需要重发时,中心会调用 reset() 让解码器丢掉上一跳的残留缓冲,因此实现不能把"第一次调用"作为初始状态 的来源。
  • 必须尊重单帧上限。当缓存超过 setMaxFrameBytes() 设定的长度仍未 出现分帧符时,实现应当丢弃该部分而不是继续累积——否则一个始终不发换行 的恶意响应就能把进程内存吃光。本模块自带的两个实现都采用"清空缓冲"的 策略。

Note: 同一实例不会被两个请求同时使用,因此实现无需考虑并发访问;但也不应 依赖"只会被一个请求用到底",重试会复用同一个 shared_ptr 实例,这也是要求 实现支持 reset() 的原因。

内置实现见 Visindigo::Network::SseDecoder(W3C text/event-stream)与 Visindigo::Network::JsonLinesDecoder(NDJSON)。

另请参阅 Visindigo::Network::StreamFrame and Visindigo::Network::HttpRequest::setStreamDecoder.

成员函数文档

[virtual noexcept, since Visindigo 0.17.0] IStreamDecoder::~IStreamDecoder()

虚析构,使调用方可以通过本接口指针安全销毁具体解码器。

中心以 std::shared_ptr 持有解码器,因此继承本接口的类只需正常实现析构即可, 不必自行管理生命周期。

这个function 从 Visindigo 0.17.0 开始支持。

[pure virtual, since Visindigo 0.17.0] QList<Visindigo::Network::StreamFrame> IStreamDecoder::feed(const QByteArray &chunk)

送入一段新到达的字节,返回本次能够完整切出的所有帧。

chunk 的边界没有任何语义,实现不得对其做任何假设:它可能是半个帧, 也可能包含若干个完整帧。未被切出的残余部分应留在内部缓冲中,等待后续 调用补齐。

返回的列表可以为空,表示本次到达的字节尚不足以构成一个完整帧。空列表是 常态而非异常,中心收到空列表时什么也不做。

这个function 从 Visindigo 0.17.0 开始支持。

[pure virtual, since Visindigo 0.17.0] QList<Visindigo::Network::StreamFrame> IStreamDecoder::finish()

在流结束时调用一次,返回缓冲中剩余内容所能构成的帧。

之所以需要这个独立的入口,是因为不少服务端在发出最后一个事件后直接断开 连接,而不补上作为结束标记的空行(SSE)或换行(NDJSON)。若只靠 feed() 分帧,这最后一份数据就会被永远留在缓冲区里。

这个function 从 Visindigo 0.17.0 开始支持。

[pure virtual, since Visindigo 0.17.0] qint64 IStreamDecoder::getBufferedBytes() const

返回尚未切分成帧的字节数。主要供诊断使用——例如排查"流一直没动静"时, 可以用它区分"对端没有发数据"与"对端发了数据但始终不构成完整帧"。

这个function 从 Visindigo 0.17.0 开始支持。

[pure virtual, since Visindigo 0.17.0] qint64 IStreamDecoder::getMaxFrameBytes() const

返回当前的缓冲长度上限。

这个function 从 Visindigo 0.17.0 开始支持。

[pure virtual, since Visindigo 0.17.0] void IStreamDecoder::reset()

清空全部内部状态,使解码器回到刚构造时的样子。

中心在重试与重定向之后、把下一跳的字节交给解码器之前调用它。如果不重置, 上一跳半途而废的字节会与下一跳的开头拼接在一起,凭空造出一个从未存在过的帧。

这个function 从 Visindigo 0.17.0 开始支持。

[pure virtual, since Visindigo 0.17.0] void IStreamDecoder::setMaxFrameBytes(qint64 bytes)

设置内部缓冲的长度上限,单位为字节。详见类说明中关于超限处理的约定。

bytes 缓冲长度上限,单位为字节。

这个function 从 Visindigo 0.17.0 开始支持。