【问题标题】:Combine two buffers into a single write on Win32 pipe将两个缓冲区合并到 Win32 管道上的单个写入中
【发布时间】:2012-12-18 15:40:16
【问题描述】:

我正在通过 Win32 命名管道实现 ZeroMQ wire format。该格式需要在消息前面加上其大小。我的界面看起来像send(std::vector<unsigned char>),因此用户已经分配了一个与其数据的确切大小相同的缓冲区,我根据vector.size() 构建大小标头。

目前我正在将大小标头以独立写入的方式发送到管道。但随后,如果实际消息内容的后续写入失败,则数据流处于错误状态,接收方期望更多数据,但发送方认为该消息失败。

我想将尺寸标头和内容合并到一个管道写入中,因此标头不会自行通过。但我想避免复制vector 的内容,因为它可能很大。有没有办法将两个缓冲区组合成一个 Win32 管道写入?

如果没有,我总是可以添加类似unsigned char *getPipeBuffer(size_t size) 的内容,为标题分配额外空间。但是最好保持界面不变。

【问题讨论】:

    标签: c++ winapi pipe named-pipes zeromq


    【解决方案1】:

    您是否考虑过使用带有PIPE_READMODE_MESSAGE 的管道?这样您就可以免费获得消息大小,而无需将其包含在消息本身中。

    写入时,写入操作只有在整个消息被写入时才完成。

    读取时,读取操作读取一条消息。或者,如果消息不适合管道缓冲区,则读取其中的一部分,然后报告有更多数据等待,并且您需要再次调用它以接收其余消息。

    不需要传递消息大小,因为接收者总是知道它何时读完一条消息。

    请注意,对于管道客户端,需要通过调用 SetNamedPipeHandleState 来更改管道读取模式。

    更多信息here

    【讨论】:

      【解决方案2】:

      我的第一反应是使用WriteFileGather,但这对您传递给函数的缓冲区对齐有严格的要求,这可能难以执行,在检查文档后似乎这可能行不通完全有管道,虽然我不明白为什么它不会。

      我认为进行两次不同的写入,一次写入大小,一次写入数据应该没问题。你问如果第二次写入失败并且流处于某种不一致的状态会发生什么,而另一端需要更多数据。但即使是单个写入请求也可能使管道处于这种状态:例如,WriteFile 写入的字节数可能少于请求的字节数,因此需要进行第二次写入,而第二次写入可能会失败。

      【讨论】:

      • 来自文档:每个缓冲区必须至少是系统内存页面的大小,并且必须在系统内存页面大小边界上对齐。这绝对行不通,因为ZeroMQ 标头是 1 或 9 个字节。不过我同意你的第二段,我想无论如何我都需要为这种问题做好准备。
      【解决方案3】:

      请注意,您用作参考的页面在开头说,“警告:此文本已被弃用,并且指的是旧版本的 ØMQ。它保留在这里是为了历史利益。不要使用这个来学习 ØMQ 。”

      这不是 0MQ 线格式。如果您想要 0MQ 线路格式,请访问 RFC 站点 http://rfc.zeromq.org/spec:15

      【讨论】:

      • 哇,感谢您让我注意到这一点。幸运的是我只是在内部使用这个协议,它不需要匹配 ZeroMQ。但这很好知道。你知道他们为什么选择改变它吗?
      猜你喜欢
      • 2023-03-06
      • 1970-01-01
      • 2018-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多