【问题标题】:boost::asio: Ordering of data sent to a socketboost::asio: 发送到套接字的数据排序
【发布时间】:2017-08-22 09:29:26
【问题描述】:

数据发送到带有 boost::asio 的套接字的顺序是否完全得到保证?

也就是说,我正在多次调用

boost::asio::async_write(socket, buffer, completionHandler)

我看到一些奇怪的行为,客户端显然没有收到我认为我正在发送的数据,所以我想确保它正在做我希望它正在做的事情。请注意,我不是在等待在每次写入之间调用完成处理程序,我只是在触发一堆 async_write 调用并天真地期望数据以相同的顺序写入套接字。

asio 中的 strand 文档说:

如果存在与连接关联的单个异步操作链(例如,在 HTTP 等半双工协议实现中),则处理程序不可能并发执行。这是一条隐含的链。

我认为这意味着使用一个链不会改变任何东西,因为套接字提供了一个隐式链。

strand 文档通常讨论事件处理程序的严格顺序调用。但是我不清楚写入连接的数据是否会按照我调用 async_write 的顺序写入。

数据写入套接字的顺序是否有保证?

【问题讨论】:

  • 这取决于底层协议。您使用的是 TCP 还是 UDP?如果您使用 TCP,您调用async_write 的顺序将是另一端接收数据的顺序。如果数据已损坏(使用 TCP 套接字),那么其他地方还有另一个问题。您要发送什么样的数据?你是怎么收到的?如何检查其有效性?
  • 另外,如果您使用 TCP,请记住它是一个 协议,没有固定大小的数据包或消息边界。接听电话可能给您少于 比您预期,或多于一个“消息”。您需要自己处理拆分成单独的消息或数据包。
  • 另一方面,如果您使用 UDP,则可能会丢失数据包,或者以错误的顺序接收数据包。
  • @Someprogrammerdude 是的,抱歉,应该澄清一下。 TCP,我只是在发送数据时将数据转储到文件中,然后在收到数据时转储数据。我对套接字编程很有经验,但我只是想解释为什么我在使用我不太熟悉的 asio 时显然没有收到我发送的内容。我想(双重)检查 asio 保证数据按照我调用 async_write 的顺序发送到连接

标签: c++ boost-asio


【解决方案1】:

不允许在另一个通话过程中拨打async_write。无论您使用的是一个线程还是多个线程,这都是正确的。来自asio docs

此操作通过对流的 async_write_some 函数的零次或多次调用来实现,称为组合操作。在此操作完成之前,程序必须确保流不执行其他写入操作(例如 async_write、流的 async_write_some 函数或执行写入的任何其他组合操作)。

编辑:解决方法是维护一个要写入的字节缓冲区,并在写入过程中添加而不是调用async_write。当前写入完成后,使用该缓冲区再次调用async_write

编辑 2:this question 的答案有一个如何执行此操作的示例。它使用 strands,因此可以在多线程应用程序中工作(但如果您的应用程序是单线程的,则它比必要的复杂一点)。

编辑 3:最后的澄清。使用 strand 无济于事,因为 strand 保证您的代码(对于该 strand)一次只在一个线程中运行,但不能保证一次只发生一个操作。换句话说,如果您在处理程序中调用async_write,那么只要该处理程序返回,就可以在该链中调用更多内容,即使async_write 仍在进行中。您需要手动存储一些表明您已启动 async_write 的状态,并且(这里是关键部分)在您作为参数传递给 async_write 的完成处理程序中更新该状态。

【讨论】:

  • 是的,我得出的结论是多次调用 async_write 而不等待响应将是一个坏主意。如果不出意外,我不会在进行下一次写入之前检查一次写入是否成功。在这种情况下,我不完全确定异步写入是否优于阻塞同步写入
  • 回想起来,我正在对其进行编程,就像我对 zeroMQ 进行编程一样,我知道我可以在其中触发发送并且它们异步发生。我真的不想维护自己的发送队列,所以同步执行写入是迄今为止最简单的解决方案。
  • 我认为如果你可以摆脱同步调用,那没有什么问题。
【解决方案2】:

你没有说你的线程,有多少线程同时发送数据? io_service.run() 有多少线程?我不知道 Asio 是否在写入套接字时进行任何同步,我认为它不是因为套接字写入已经是线程安全的。

我建议检查数据缓冲区(发送到套接字的缓冲区)或数据接收逻辑上的数据竞争。

此外,TCP 流式传输特性(如 cmets 中提到的 @Some_programmer_dude)是一个常见的混淆来源。

【讨论】:

    猜你喜欢
    • 2011-10-07
    • 1970-01-01
    • 2011-10-15
    • 2011-12-05
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    相关资源
    最近更新 更多