我可以使用 Boost.Asio 在多线程 I/O 服务上同步读取套接字并设置超时吗?

2023-11-23

我有一个使用 Boost.Asio 进行 TCP 和 UDP 套接字通信的应用程序。我知道“Asio”中的“A”代表异步,因此该库致力于鼓励您尽可能使用异步 I/O。我有一些情况,同步套接字读取更可取。但与此同时,我想为所述接收调用设置超时,因此不可能无限期地阻塞读取。

这似乎是 Boost.Asio 用户中非常常见的问题,过去 Stack Overflow 曾就该主题提出过以下问题:

  • C++ Boost ASIO:如何超时读/写?
  • asio::读取超时
  • 提高asio超时
  • 如何在 boost asio 中设置阻塞套接字的超时?

甚至可能还有更多。甚至还有文档中的示例了解如何实现带超时的同步操作。它们归结为将同步操作转换为异步操作,然后与异步操作并行启动它asio::deadline_timer。如果超时到期,计时器的到期处理程序可以取消异步读取。这看起来像这样(摘自上面链接示例的片段):

std::size_t receive(const boost::asio::mutable_buffer& buffer,
      boost::posix_time::time_duration timeout, boost::system::error_code& ec)
  {
    // Set a deadline for the asynchronous operation.
    deadline_.expires_from_now(timeout);

    // Set up the variables that receive the result of the asynchronous
    // operation. The error code is set to would_block to signal that the
    // operation is incomplete. Asio guarantees that its asynchronous
    // operations will never fail with would_block, so any other value in
    // ec indicates completion.
    ec = boost::asio::error::would_block;
    std::size_t length = 0;

    // Start the asynchronous operation itself. The handle_receive function
    // used as a callback will update the ec and length variables.
    socket_.async_receive(boost::asio::buffer(buffer),
        boost::bind(&client::handle_receive, _1, _2, &ec, &length));

    // Block until the asynchronous operation has completed.
    do io_service_.run_one(); while (ec == boost::asio::error::would_block);

    return length;
  }

这实际上是一个相对干净的解决方案:启动异步操作,然后手动轮询asio::io_service一次执行一个异步处理程序,直到async_receive()完成或计时器到期。

然而,如果套接字的底层 I/O 服务已经在一个或多个后台线程中运行,情况会怎样呢?在这种情况下,无法保证异步操作的处理程序将由上面代码片段中的前台线程运行,因此run_one()直到稍后某个可能不相关的处理程序执行后才会返回。这将使套接字读取相当无响应。

asio::io_service has a poll_one()函数将在不阻塞的情况下检查服务的队列,但我没有找到阻止前台线程(模拟同步调用行为)直到处理程序执行的好方法,除了没有正在执行的后台线程的情况之外asio::io_service::run()已经。

我看到了两种可能的解决方案,但我都不喜欢:

  1. 使用条件变量或类似的构造使前台线程在启动异步操作后阻塞。在处理程序中async_receive()调用,向条件变量发出信号以解除线程阻塞。这会导致每次读取时出现一些锁定,我希望避免这种情况,因为我希望在 UDP 套接字读取上实现最大可能的吞吐量。否则,它是可行的,并且可能是我会做的,除非出现更好的方法。

  2. 确保套接字有自己的asio::io_service没有由任何后台线程运行。这使得在需要的情况下使用套接字的异步 I/O 变得更加困难。

有什么其他方法可以安全地实现这一目标吗?


Aside:对于之前的 SO 问题,有一些答案提倡使用SO_RCVTIMEO套接字选项来实现套接字读取超时。这在理论上听起来很棒,但它似乎至少在我的平台上不起作用(Ubuntu 12.04,Boost v1.55)。我可以设置套接字超时,但它不会给 Asio 带来预期的效果。相关代码在/boost/asio/detail/impl/socket_ops.ipp:

size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
    size_t count, int flags, socket_addr_type* addr,
    std::size_t* addrlen, boost::system::error_code& ec)
{
  if (s == invalid_socket)
  {
    ec = boost::asio::error::bad_descriptor;
    return 0;
  }

  // Read some data.
  for (;;)
  {
    // Try to complete the operation without blocking.
    signed_size_type bytes = socket_ops::recvfrom(
        s, bufs, count, flags, addr, addrlen, ec);

    // Check if operation succeeded.
    if (bytes >= 0)
      return bytes;

    // Operation failed.
    if ((state & user_set_non_blocking)
        || (ec != boost::asio::error::would_block
          && ec != boost::asio::error::try_again))
      return 0;

    // Wait for socket to become ready.
    if (socket_ops::poll_read(s, 0, ec) < 0)
      return 0;
  }
}

如果套接字读取超时,则调用recvfrom()上面会返回EAGAIN or EWOULDBLOCK,它被翻译成boost::asio::error::try_again or boost::asio::error::would_block。在这种情况下,上面的代码将调用poll_read()函数,对于我的平台来说是这样的:

int poll_read(socket_type s, state_type state, boost::system::error_code& ec)
{
  if (s == invalid_socket)
  {
    ec = boost::asio::error::bad_descriptor;
    return socket_error_retval;
  }

  pollfd fds;
  fds.fd = s;
  fds.events = POLLIN;
  fds.revents = 0;
  int timeout = (state & user_set_non_blocking) ? 0 : -1;
  clear_last_error();
  int result = error_wrapper(::poll(&fds, 1, timeout), ec);
  if (result == 0)
    ec = (state & user_set_non_blocking)
      ? boost::asio::error::would_block : boost::system::error_code();
  else if (result > 0)
    ec = boost::system::error_code();
  return result;
}

我剪掉了为其他平台有条件编译的代码。正如你所看到的,如果套接字不是非阻塞套接字,它最终会调用poll()具有无限超时,因此会阻塞,直到套接字有数据要读取(并在超时时阻止尝试)。就这样SO_RCVTIMEO选项无效。


Boost.Asio 的支持futures可能会提供一个优雅的解决方案。当提供异步操作时boost::asio::use_futurevalue 作为其完成处理程序,启动函数将返回一个std::future将接收操作结果的对象。此外,如果操作失败完成,error_code被转换成system_error并通过future.

在 Boost.Asio C++11 期货中日期时间客户端示例,一个专用线程运行io_service,主线程发起异步操作,然后同步等待操作完成,如下:

std::array<char, 128> recv_buf;
udp::endpoint sender_endpoint;
std::future<std::size_t> recv_length =
  socket.async_receive_from(
      boost::asio::buffer(recv_buf),
      sender_endpoint,
      boost::asio::use_future);

// Do other things here while the receive completes.

std::cout.write(
    recv_buf.data(),
    recv_length.get()); // Blocks until receive is complete.

使用时futures,实现带超时的同步读取的总体方法与之前相同。可以使用异步读取并异步等待计时器,而不是使用同步读取。唯一的小变化是,而不是阻塞io_service或者定期检查谓词,可以调用future::get()阻塞直到操作成功或失败(例如超时)完成。

如果C++11不可用,那么可以为Boost.Thread自定义异步操作的返回类型future,如所示this answer.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我可以使用 Boost.Asio 在多线程 I/O 服务上同步读取套接字并设置超时吗? 的相关文章

  • 如何延长SQL查询的超时时间

    这不是连接超时 因为与数据库的连接正常 问题是我调用的存储过程花费的时间超过 30 秒 并导致超时 该函数的代码如下所示 SqlDatabase db new SqlDatabase connectionManager SqlConnect
  • 如何使用C从http下载文件?

    最近几天我试图弄清楚如何从 URL 下载文件 这是我对套接字的第一个挑战 我用它来了解协议 所以我想在没有 cURL 库的情况下只用 C 语言来完成它 我搜索了很多 现在我可以打印页面的源代码 但我认为这与文件不同 我不必只将接收到的数据从
  • HtmlUnit WebClient 超时

    在我之前关于 HtmlUnit 的问题中跳过 HTML 单元中特定的 Javascript 执行 https stackoverflow com questions 14439991 skip particular javascript e
  • C# 套接字数据报溢出

    我是 C 新手 我有一个关于udp套接字的小问题 我有一个聊天服务器 它接收特定结构的数据包 udp 数据报 为什么程序在套接字缓冲区已满时才接收数据 难道以后的一切就不应该失去吗 也许会出现数据包碎片 数据包结构 udp headers
  • C# 中方法的时间限制

    我有一个游戏框架 其中有一个实现 IBotInterface 的机器人列表 这些机器人是由用户定制的 唯一的限制是它们必须实现接口 然后游戏会调用机器人中的方法 希望是并行的 来处理各种事件 例如 yourTurn 和 roundStart
  • 连接广播而不是服务器后AsyncUdpSocket接收数据的小问题

    我的 AsyncUdpSocket 有问题 我曾经连接到服务器 发送一些数据并获得一些响应 现在 由于我不知道服务器的实际地址 我不得不更改代码并将数据发送到广播地址 255 255 255 255 这是我的代码 NSString bcho
  • Ubuntu:无法通过套接字“/var/run/mysqld/mysqld.sock”连接到本地 MySQL 服务器 (2)

    我有 Ubuntu 14 04 安装了 LAMP 并运行 Owncloud 的服务器 我尝试安装文书工作 https github com twostairs paperwork wiki Installing Paperwork on U
  • winsock 和 BSD 套接字实现之间的差异

    Winsock 和 nix BSD 套接字实现之间的主要区别是什么 你可能想看看here http tangentsoft net wskfaq articles bsd compatibility html 为此 我要放弃一个区别 win
  • 如何将 boost::asio 套接字转换为 C++/CLI .Net 套接字?

    我想要的是简单的 从 boost asio 套接字创建新的 C CLI Net 套接字的代码示例 如何创建这样的东西 这是我想做的伪代码 net socket a boost asio socket b a assign b nativeW
  • 在本地主机上使用相同的 IP 和端口创建套接字

    我在 Linux 上看到奇怪的行为 我看到远程端和本地端都显示相同的 IP 和端口组合 以下是 netstat 输出 netstat anp 网络统计grep 6102 tcp 0 0 139 185 44 123 61020 0 0 0
  • 如何在不超时的情况下解析大型 CSV 文件?

    我正在尝试解析 50 MB 的 csv 文件 文件本身很好 但我正在尝试解决所涉及的大量超时问题 每个设置上传明智 我可以轻松上传并重新打开文件 但浏览器超时后 我收到 500 内部错误 我的猜测是我可以将文件保存到服务器上 打开它并保留我
  • Chrome 在传输一定量的数据后挂起 - 等待可用的套接字

    我有一个浏览器游戏 最近我开始向游戏添加音频 Chrome 无法加载整个页面并卡在 91 requests 8 1 MB transferred 并且不再加载任何内容 它甚至破坏了所有其他选项卡中的网站 说Waiting for avail
  • 跨 NAT 的 UDP 客户端无法从服务器接收数据

    我正在尝试在服务器 在公共 IP 上 和客户端 跨 NAT 之间使用 UDP 进行双向通信 我的逻辑是 如果服务器将一些数据发送到 IP 和它接收数据包的端口 客户端仍然应该收到它 因为 NAT 将具有最终将数据包发送到客户端的映射 客户端
  • Memcachier 达到缓存限制时 Heroku 请求超时

    我使用 Memcachier Dalli 作为客户端 将 Rails 应用程序部署到 Heroku 我正在使用免费插件 提供 25 MB 缓存 我们开始收到来自heroku的请求超时 经过调试 我们发现手动刷新Memcachier解决了问题
  • 当我退出应用程序时,如何删除 UNIX 域套接字文件?

    我有一个服务器应用程序 它在特定路径中创建一个 UNIX 域套接字 其名称和bind 到它 仅当我有意从应用程序代码中关闭 停止应用程序时 我才需要删除套接字 否则需要打开 我该怎么做呢 Thanks Edit 考虑一下我从终端内部启动并运
  • 将一个整数从 C 客户端发送到 Java 服务器

    我使用此代码将一个整数从我的 Java 客户端发送到我的 Java 服务器 int n rand nextInt 50 1 DataOutputStream dos new DataOutputStream socket getOutput
  • 从物理上来说,套接字是什么?

    我总是更喜欢编程概念的物理含义而不是其逻辑含义 那么这个问题就来了 当我回顾套接字编程范例时 我注意到bind 连接 函数所做的就像tuning由创建的套接字socket 功能 所以我想那是什么socket 函数所做的只是创建一个数据结构
  • 无需超级用户即可在 Linux 中打开 RAW 套接字

    我必须编写一个在 Linux 上运行的 ping 函数 语言是 C 所以 C 也可以 在网上搜索并查看源代码ping命令 事实证明我应该创建一个原始套接字 icmp sock socket AF INET SOCK RAW IPPROTO
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • 程序退出后,TcpListener Socket 仍处于活动状态

    当我的程序退出时 我试图停止 TCP 侦听器 我不关心套接字或任何活动客户端套接字上当前活动的任何数据 套接字清理代码本质上是 try myServer Server Shutdown SocketShutdown Both catch E

随机推荐

  • 制作 USB 设备,用 Java 控制它

    I m thinking about making a physical controller device with knobs buttons and LEDs I d like to interact with it using Ja
  • 您可以在代码中配置 log4net 而不是使用配置文件吗?

    我明白为什么 log4net 使用app config用于设置日志记录的文件 因此您可以轻松更改信息的记录方式 而无需重新编译代码 但就我而言 我不想打包app config文件与我的可执行文件 而且我不想修改我的日志记录设置 有没有办法让
  • 如何从 Eclipse 导入包?

    在我的目录之一中 我拥有属于一个包 游戏 的所有 java 文件 现在我想创建一个不属于该包并导入 game 包的 java 文件 如果我创建一个新文件并写入import game 然后 Eclipse 抱怨它不知道 游戏 包的含义 有人可
  • Webstorm 的 Sass 文件观察器

    我正在尝试在 NodeJS 项目中使用 sass 这是我使用 nodejs 安装的库 https www npmjs org package node sass 我在这个项目中使用 webstorm 但无法让 Sass 文件观察器工作 即使
  • 从脚本与命令行在节点中分配全局变量

    我有以下脚本 script js var bar bar1 function foo console log this bar this bar console log global bar global bar foo Running n
  • 为什么在 Windows 中命名文件“con.txt”会使 Python 写入控制台而不是文件?

    我需要帮助调试 Python 中的一些奇怪的文件行为 采取以下脚本 write con py f open con txt w f write hi 在 Linux 中 这会创建一个名为con txt与内容hi 在 Windows 中这样写
  • 电路/方框图绘制

    我正在寻找用于 漂亮的 电路 框图绘制的算法或可视化工具 我也对这个问题的一般表述感兴趣 我所说的 电路绘图 是指利用 I O 端口及其连接 电线 探索框图 矩形 的位置和路线的能力 这些框图可以是分层的 即某些块可能具有一些嵌套的内部子结
  • 将 Word 文档文本转换为 HTML 的库 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 是否有一个 Net开源库可以将word文档转换为HTML以在网页内显示 我知道有几种将 word 文档转换为 html 文件的工具 但我的要求是在
  • Rails 3.1 身份映射问题?

    有谁知道 Rails 3 1 IdentityMap 功能的关键问题导致默认情况下强制禁用该功能 我确信存在一些小具体问题 但是在为已构建的 Rails 3 1 应用程序启用它之前 是否有任何人应该注意的重大问题 来自代码中的注释 Acti
  • python-opencv AttributeError:“模块”对象没有属性“createBackgroundSubtractorGMG”

    我正在尝试遵循以下中给出的教程 https opencv python tutroals readthedocs org en latest py tutorials py video py bg subtraction py bg sub
  • 在 Mac OS 上设置 tkinter 图标

    我正在尝试更改 Mac OS 的 tk 应用程序上显示的图标 上次我检查此代码适用于 Windows 目标是使该解决方案能够跨所有平台工作 root tk Tk app Application master root app master
  • Clion 无法识别我的快速工具链路径

    我正在尝试为 swift 项目配置 clion 但它无法识别 swift 工具链路径 which swift 产生输出 usr bin swift bin swift 所以工具链就在那里 但 clion 只是不认识它 我该如何进行这项工作
  • jQuery 工具提示 onClick?

    我已经找了很长时间了 似乎找不到一个使用以下内容的 jQuery 工具提示插件 onClick 代替hover 使其像切换按钮一样工作 淡入淡出 使用工具提示的想法是 我有一些想要在其中显示内容的链接 虽然普通的工具提示 这可能是我出错的地
  • 如何在 Windows 上安装 pip?

    pip是替代品easy install 但我应该安装pip using easy install在 Windows 上 有没有更好的办法 Python 3 4 和 2 7 9 好消息 Python 3 4 2014 年 3 月发布 和Pyt
  • MySQL 表的主键是否应该公开?

    我有许多描述模型的 MySQL 表 例如 用户 业务 等 这些表的主键是否应该暴露给客户端 我主要是从安全角度来问 但是还有其他我没有想到的考虑因素吗 暴露您的主键 特别是如果它们是可预测的 是一个称为不安全直接对象引用的漏洞 通过使用如下
  • 如何设置 NSDate 上的时间?

    我想用我想要的小时 分钟 秒设置 NSDate 时间 目前我正在使用 NSDate 组件 但它没有给出期望的结果 comps setHour hours comps setMinute 0 comps setSecond 0 NSDate
  • 有人有 SourceForge 的 Xselerator XSL IDE 副本吗? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 我多年来一直使用 Marrowsoft Xselera
  • 使用 python pandas 比较两个 csv 文件

    我有两个 csv 文件 均由两列组成 第一个具有产品 ID 第二个具有序列号 我需要查找第一个 csv 中的所有序列号 并在第二个 csv 上查找匹配项 结果报告将在单独的列中包含匹配的序列号以及每个 csv 中相应的产品 ID 我确实修改
  • ASP.NET MVC 4 C# HttpPostedFileBase,如何存储文件

    Model public partial class Assignment public Assignment this CourseAvailables new HashSet
  • 我可以使用 Boost.Asio 在多线程 I/O 服务上同步读取套接字并设置超时吗?

    我有一个使用 Boost Asio 进行 TCP 和 UDP 套接字通信的应用程序 我知道 Asio 中的 A 代表异步 因此该库致力于鼓励您尽可能使用异步 I O 我有一些情况 同步套接字读取更可取 但与此同时 我想为所述接收调用设置超时