【问题标题】:boost::asio::read() never returns, even after a write() has been executed successfully on the other endboost::asio::read() 永远不会返回,即使在另一端成功执行了 write() 之后
【发布时间】:2011-12-09 01:27:00
【问题描述】:

我正在尝试学习 boost::asio 以进行套接字/网络编程。我正在尝试将一些简单的数据从客户端发送到服务器。

首先让我说一下,我有意使用同步的阻塞代码,而不是异步的非阻塞代码,因为我还使用了多线程(使用 pthreads 库)到这个。

客户端成功调用 boost::asio::write()。我不仅尝试捕获 boost::asio::write() 抛出的任何异常,而且还检查了 boost::system::error_code 值,它给出了一条消息“操作已经成功完成”或类似的东西。

我的 read() 代码如下所示:

#define MAX_MESSAGE_SIZE 10000 // in bytes
void* receivedData = malloc(MAX_MESSAGE_SIZE);

try
{
    boost::asio::read(*sock, boost::asio::buffer(receivedData, MAX_MESSAGE_SIZE));
}
catch (std::exception &e)
{
    std::cout << "Exception thrown by boost::read() in receiveMessage(): " << e.what() << "\n";
    delete receivedData;
    receivedData = NULL;
    return false;
}

尽管 write() 在另一端成功执行,并且客户端和服务器都同意此时已建立连接,但 read() 永远不会返回。它返回给我的唯一情况是,如果我手动关闭客户端应用程序,此时(正如预期的那样),read() 调用会引发异常,指出客户端已强制关闭连接。

和io_service.run()有关系吗?在我的谷歌搜索调试中,我遇到了一些关于 run() 的提及,我从这些帖子中隐含地收集到 run() 处理“工作”,我认为这意味着它执行实际的发送和接收,并且 write() 和 read() 只是排队发送和检查哪些数据包已经发送和“批准”的手段,可以说,由 io_service.run()。如果我错了,请纠正我,因为 Boost 文档只说“运行 io_service 的事件处理循环”。

我正在关注 boost::asio 教程(http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/tutorial/tutdaytime1.html),它完全没有提到 run(),所以也许我在这里完全走错了路,run() 根本没有必要?

无论哪种方式,刚才我对我的代码进行了另一项更改,以查看是否有任何更改(它没有更改):在我的客户端和服务器中,我为以下函数设置了一个线程(调用 io_service.run () 在整个应用程序的持续时间内重复,看看是否不这样做是导致问题的原因):

void* workerThread(void* nothing)
{
    while(1)
    {
        io_service.run();
        Sleep(10); // just keeping my CPU from overheating in this infinite loop
    }
}

但如上所述,这根本不影响性能。

我在这里缺少什么?为什么 read() 永远不会返回,即使在另一端的 write() 已经成功执行之后?

提前致谢。

【问题讨论】:

    标签: multithreading boost-asio blocking


    【解决方案1】:

    请注意,您正在使用的读取将阻塞,直到缓冲区已满或发生错误 - 所以它只会在收到 10000 个字节时返回。

    考虑使用 read_some 或使用带有 read 的完成条件。

    【讨论】:

    • 啊哈,你说得对。将其设置为 1 而不是 10000,或者例如,有效。您能否详细说明如何使用 read_some(),或者我将如何使用 read() 的完成条件?如果我使用这些,我是否可以确保我的完整“读取”将是在 write() 中发送的完整且准确的数据,或者我是否需要在每条消息前面加上一个字节,告诉接收者消息有多少字节是(并继续读取和存储数据,直到收到完整的消息)?
    • 使用 TCP 套接字,您不能依赖保留的数据包边界,因此您必须使用自己的协议。最简单的方法可能是对消息头和消息体使用单独的读取调用(使用 transfer_exactly 和消息头的大小)。
    • 哦,我明白了,是的,这听起来很简单,而且效果很好。非常感谢您的帮助!
    猜你喜欢
    • 2015-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    相关资源
    最近更新 更多