Boost::Asio异步写入失败
Boost::Asio Async write failed
我正在将一个使用Boost::Asio的应用程序移植到嵌入式系统。
我已经使用它的BSP为板交叉编译了boost 1.57.0二进制文件。为了测试库的工作情况,我运行了两个http服务器示例,分别使用同步和异步编写。
Sync版本运行良好;而异步的写入失败。返回错误"操作已取消"。
有人能指出我应该去哪里吗?谢谢
/*
* 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
指针添加到绑定参数来修复它,或者在CSession
类型中使用enable_shared_from_this
习惯用法。
使用更多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";
}
应该像这样绑定:
psocket->async_write_some(ba::buffer(*pstr),
boost::bind(&CService::write_handler, this, pstr, psocket,
ba::placeholders::error, ba::placeholders::bytes_transferred));
在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;
};
现在绑定看起来像:
boost::bind(&CSession::write_handler,
shared_from_this(), /* keep-alive! */
ba::placeholders::error, ba::placeholders::bytes_transferred)
简单多了。会话管理由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();
}
}
再次在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();
}
输出类似。
相关文章:
- 如果没有malloc,链表实现将失败
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 视图中的参数推导失败:take_while
- 链接到自行创建的dll失败
- 带有特殊路径部分的"std::filesystem::weakly_canonical"失败
- GetShortPathName在网络驱动器上使用中文文件夹时失败
- gcc和c++17的过载解析失败
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 在WSL:configure_file上对config_file的每次调用都失败:配置文件时出现问题
- 使用 GCC 卸载的 OpenMP 卸载失败,并出现"Ptx assembly aborted due to errors"
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 从父数组测试用例构造二叉树失败
- LibGit2 SSH身份验证失败
- 如何让LLDB在成功时退出,在失败时等待
- VS2017,C++包含目录与附加包含目录,子文件夹包含失败-但为什么
- Boost Beast 异步服务器失败,断言失败:(id_ != T::id) 在多个 aync 调用中
- Boost::Asio异步写入失败