我有 2 个通过网络链接进行通信的应用程序。发送方将使用 zlib 的 deflate() 压缩数据包并通过网络发送。然后接收器将使用 inflate() 解压缩数据。网络链路上的数据包可能会丢失;为了最大限度地减少解压错误,我实现了以下方法:
发件人
大部分时间都使用 Z_SYNC_FLUSH 调用 deflate(),但间歇性地使用 Z_FULL_FLUSH 调用 deflate()。
发送(与数据一起)一个 2 字节字段,其中包含一个指示是否使用 FULL_FLUSH 或 SYNC_FLUSH 的位以及一个序列号。
接收者
- 读入数据;并使用序列号检测是否 数据包已丢失。当没有数据包丢失时,2个字节是 删除后解压正常。
当检测到数据包丢失时,接收方检查是否 当前数据包是 FULL_FLUSH 或 SYNC_FLUSH 数据包。
如果是 SYNC_FLUSH,则数据包将被简单地丢弃,我们将继续处理下一个数据包。
如果是 FULL_FLUSH;然而,接收方会删除多余的 2 个字节并调用 inflate()。
这在 99% 的情况下都有效;从某种意义上说,inflate() 成功,并且未压缩的数据确实与发送者压缩之前的数据相同。这是我的期望!
偶尔;然而,这种方法使接收器处于不良状态,其中每个后续数据包(包括 FULL_FLUSH 数据包)都无法解压缩。 inflate() 返回 Z_DATA_ERROR 并且 zlibContext.zstream.msg 包含“错误的 header 检查”;尽管我偶尔会收到“无效距离太远”的消息。
我的第一个问题是
Should I expect to recover and inflate() successfully when the packet at hand was compressed using a FULL_FLUSH flush mode; even if previous packets were lost? For example, sender compresses using
deflate(ctx, SYNC_FLUSH)
the first 3 packets and sends them; one at a time, over the network. The sender then compresses the fourth packet usingdeflate(ctx, FULL_FLUSH)
and sends it across the network. The receiver receives packet 1 & 2 and callsinflate()
with success. The receiver then receives packet 4; it detects (via the sequence #) that it has missed packet 3. Since packet 4 was compressed using a FULL_FLUSH, the receiver expects that theinflate()
will successfully decompress the packet. Is this a valid assumption?
我的第二个问题是
Is there anything else I need to do in in the receiver to be able recover from packet loss and continue decompressing packets?
最佳答案
你的逻辑有点错误。 FULL_FLUSH 数据包进行完全刷新。在该数据包之后,状态将被刷新。通过处理FULL_FLUSH
数据包,您正在尝试执行刷新 - 但您不能,因为您没有正确的状态来执行刷新。
但是,您可以在刷新后继续。因为在刷新之后,状态就被刷新了。
因此,在丢失后,您不想处理FULL_FLUSH
数据包,因为您没有处理它所需的上下文。但是,在该数据包之后,状态已完全刷新,因此您可以使用下一个数据包恢复通货膨胀。
所以你的丢包逻辑应该是:
- 等待,直到收到设置了 FULL_FLUSH 位的数据包。
- 等待下一个数据包。
- 如果 FULL_FLUSH 数据包和此数据包之间没有丢失数据包,则从此数据包开始恢复膨胀(使用干净的上下文!)。
关于c++ - zlib inflate() 和网络链接上的数据丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39171580/