gpt4 book ai didi

c++ - Boost::Asio 异步写入失败

转载 作者:搜寻专家 更新时间:2023-10-31 02:20:26 26 4
gpt4 key购买 nike

我正在将使用 Boost::Asio 的应用程序移植到嵌入式系统。

我已经使用其 BSP 为开发板交叉编译了 boost 1.57.0 二进制文件。为了测试库的工作情况,我运行了两个分别使用同步和异步写入的 http 服务器示例。

同步版本运行良好;而异步的写入失败。它返回错误“操作已取消”。

谁能指出我应该寻找的地方?谢谢。

/*
* Boost::Asio async example
*/
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/smart_ptr.hpp>

using namespace boost::asio;
using boost::system::error_code;
using ip::tcp;

struct CHelloWorld_Service
{
CHelloWorld_Service(io_service &iosev)
:m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 1000))
{}

void start()
{
boost::shared_ptr<tcp::socket> psocket(new tcp::socket(m_iosev));
m_acceptor.async_accept(*psocket,
boost::bind(&CHelloWorld_Service::accept_handler, this, psocket, _1));
}

void accept_handler(boost::shared_ptr<tcp::socket> psocket, error_code ec)
{
if(ec) return;
start();
std::cout << psocket->remote_endpoint().address() << std::endl;
boost::shared_ptr<std::string> pstr(new std::string("hello async world!"));
psocket->async_write_some(buffer(*pstr),
boost::bind(&CHelloWorld_Service::write_handler, this, pstr, _1, _2));
}

void write_handler(boost::shared_ptr<std::string> pstr, error_code ec,
size_t bytes_transferred)
{
if(ec)
std::cout<< "Failed to send! " << boost::system::system_error(ec).what() << std::endl;
else
std::cout<< *pstr << " has been sent" << std::endl;
}

private:
io_service &m_iosev;
ip::tcp::acceptor m_acceptor;
};

int main(int argc, char* argv[])
{
io_service iosev;
CHelloWorld_Service sev(iosev);
sev.start();
iosev.run();

return 0;
}

最佳答案

在您的 async_write_some 上调用你忘记持有对套接字实例的引用。

这会导致 socket要销毁的对象,并且作为析构函数的一部分,所有挂起的异步操作都将被取消。这说明您收到了 ec operation_aborted .

通过添加 socket 来修复它指向绑定(bind)参数的指针,或者使用 enable_shared_from_this与你成语CSession类型。

使用更多 shared_pointer魔法:

这是“最简单”的编辑:

void write_handler(
boost::shared_ptr<std::string> pstr,
boost::shared_ptr<tcp::socket> /*keepalive!*/,
error_code ec, size_t bytes_transferred)
{
if(ec)
std::cout<< "Failed to send! " << boost::system::system_error(ec).what() << "\n";
else
std::cout<< *pstr << " has been sent (" << bytes_transferred << " bytes transferred)\n";
}

应该像这样绑定(bind):

    psocket->async_write_some(ba::buffer(*pstr),
boost::bind(&CService::write_handler, this, pstr, psocket,
ba::placeholders::error, ba::placeholders::bytes_transferred));

Live On Coliru

几个样式改进

  • 不是using namespace
  • 使用asio占位符(不是 _1 , _2 )

打印:

g++ -std=c++11 -O2 -Wall -pedantic main.cpp -pthread -lboost_system -lboost_filesystem && ./a.out& while sleep .1; do nc 127.0.0.1 6767; done
127.0.0.1
hello async world!hello async world! has been sent (18 bytes transferred)
127.0.0.1
hello async world!hello async world! has been sent (18 bytes transferred)
127.0.0.1
hello async world!hello async world! has been sent (18 bytes transferred)
...

使用CSession (enable_shared_from_this)

这是另一个习语,它避免拼写出所有共享指针。

不是保留指向套接字和缓冲区的单独共享指针,而是创建一个包含两者的类:

struct CSession : boost::enable_shared_from_this<CSession> {
CSession(ba::io_service &iosev)
:m_iosev(iosev), m_sock(m_iosev)
{}

void do_response();

private:
void write_handler(error_code ec, size_t bytes_transferred);

ba::io_service &m_iosev;
tcp::socket m_sock;
std::string response;
};

现在绑定(bind)看起来像:

boost::bind(&CSession::write_handler,
shared_from_this(), /* keep-alive! */
ba::placeholders::error, ba::placeholders::bytes_transferred)

简单多了。 session 管理是CService的责任,像以前一样:

void start()
{
auto session = boost::make_shared<CSession>(m_iosev);
m_acceptor.async_accept(session->m_sock,
boost::bind(&CService::accept_handler, this, session, ba::placeholders::error));
}

void accept_handler(boost::shared_ptr<CSession> session, error_code ec) {
if(ec) {
std::cerr << "Accept failed: " << ec.message() << "\n";
} else {
session->do_response();
start();
}
}

再次 Live On Coliru

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>

namespace ba = boost::asio;
using boost::system::error_code;
using ba::ip::tcp;

namespace HelloWorld {

struct CSession : boost::enable_shared_from_this<CSession> {
CSession(ba::io_service &iosev)
:m_iosev(iosev), m_sock(m_iosev)
{}

void do_response() {
response = "hello async world!\n";
std::cout << m_sock.remote_endpoint().address() << std::endl;

m_sock.async_write_some(ba::buffer(response),
boost::bind(&CSession::write_handler,
shared_from_this(), /* keep-alive! */
ba::placeholders::error, ba::placeholders::bytes_transferred));
}

private:

void write_handler(error_code ec, size_t bytes_transferred)
{
if(ec)
std::cout<< "Failed to send! " << boost::system::system_error(ec).what() << "\n";
else
std::cout<< response << " has been sent (" << bytes_transferred << " bytes transferred)\n";
}

ba::io_service &m_iosev;

friend class CService;
tcp::socket m_sock;

std::string response;
};

struct CService
{
CService(ba::io_service &iosev)
:m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 6767))
{}

void start() {
auto session = boost::make_shared<CSession>(m_iosev);
m_acceptor.async_accept(session->m_sock,
boost::bind(&CService::accept_handler, this, session, ba::placeholders::error));
}

void accept_handler(boost::shared_ptr<CSession> session, error_code ec) {
if(ec) {
std::cerr << "Accept failed: " << ec.message() << "\n";
} else {
session->do_response();
start();
}
}

private:
ba::io_service &m_iosev;
tcp::acceptor m_acceptor;
};
}

int main() {
ba::io_service iosev;

using namespace HelloWorld;

CService sev(iosev);
sev.start();
iosev.run();
}

具有相似的输出。

关于c++ - Boost::Asio 异步写入失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32723618/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com