的boost ::短耳异步写入失败 [英] Boost::Asio Async write failed
问题描述
我端起它使用的boost ::短耳到嵌入式系统中的应用程序。
我已经交叉编译升压1.57.0的二进制文件使用的BSP板。为了测试库工作,我跑了使用同步的两个HTTP服务器实例和异步写入分别
该版本同步运行罚款;而异步逐一写失败。它返回的错误操作被取消。
任何人都可以指出我应该在哪里找?谢谢你。
/ *
*升压短耳::例如异步
* /
#包括LT&;&iostream的GT;
#包括LT&;串GT;
#包括LT&;升压/ asio.hpp>
#包括LT&;升压/ bind.hpp>
#包括LT&;升压/ smart_ptr.hpp>使用空间boost :: ASIO;
使用boost ::系统::错误_ code;
使用IP :: TCP;结构CHelloWorld_Service
{
CHelloWorld_Service(io_service对象和放大器; iosev)
:m_iosev(iosev),m_acceptor(iosev,TCP ::端点(TCP :: V4(),1000))
{} 无效的start()
{
提高:: shared_ptr的< TCP ::插座> psocket(新的TCP ::插座(m_iosev));
m_acceptor.async_accept(* psocket,
提高::绑定(安培; CHelloWorld_Service :: accept_handler,为此,psocket,_1));
} 无效accept_handler(提高:: shared_ptr的< TCP ::插座> psocket,错误_ code EC)
{
如果(EC)的回报;
开始();
性病::法院LT&;< psocket-方式> remote_endpoint()地址()&所述;&下;的std :: ENDL;
提高:: shared_ptr的<标准::字符串> PSTR(新标准::字符串(你好异步的世界!));
psocket-> async_write_some(缓冲(* PSTR)
提高::绑定(安培; CHelloWorld_Service :: write_handler,为此,PSTR,_1,_2));
} 无效write_handler(提高:: shared_ptr的<标准::字符串> PSTR,错误_ code EC,
为size_t bytes_transferred)
{
如果(EC)
性病::法院LT&;< 发送失败!<<提高::系统:: SYSTEM_ERROR(EC)。什么()<<的std :: ENDL;
其他
性病::法院LT&;< * PSTR<< 已发送<<的std :: ENDL;
} 私人的:
io_service对象和放大器; m_iosev;
IP :: TCP ::受体m_acceptor;
};INT主(INT ARGC,CHAR *的argv [])
{
io_service对象iosev;
CHelloWorld_Service SEV(iosev);
sev.start();
iosev.run(); 返回0;
}
在你的 async_write_some
叫你忘了抱到插座实例的引用。
这使得插座
对象进行破坏,并作为析构函数的一部分,所有未决的异步操作将被取消。这说明您收到 EC
operation_aborted
。
加入插座
指针已绑定参数修正,要么,或者使用 enable_shared_from_this
成语与 CSession
键入
使用的更多的 shared_pointer
魔法:
这里的简单编辑:
无效write_handler(
提高:: shared_ptr的<标准::字符串> PSTR,
提高:: shared_ptr的< TCP ::插座> /*活着!*/,
错误_ code EC,为size_t bytes_transferred)
{
如果(EC)
性病::法院LT&;< 发送失败!<<提高::系统:: SYSTEM_ERROR(EC)。什么()<< \\ n;
其他
性病::法院LT&;< * PSTR<< 已发送(<< bytes_transferred<<传输的字节)\\ n;
}
这应该绑定,如:
psocket-> async_write_some(BA ::缓冲区(* PSTR)
提高::绑定(安培;内部CService :: write_handler,为此,PSTR,psocket,
巴::占位符::错误,BA ::占位符:: bytes_transferred));
<大骨节病> 住在Coliru 骨节病>
几个样式改进
- 不是
使用命名空间
- 使用
ASIO
占位符(不_1
,_2
)
打印:
G ++ -std = C ++ 11 -O2 -Wall -pedantic的main.cpp -pthread -lboost_system -lboost_filesystem&放大器;&安培; ./a.out&而睡眠.1;做NC 127.0.0.1 6767; DONE
127.0.0.1
你好异步世界你好!异步的世界!已发送(18字节传输)
127.0.0.1
你好异步世界你好!异步的世界!已发送(18字节传输)
127.0.0.1
你好异步世界你好!异步的世界!已发送(18字节传输)
...
使用 CSession
(enable_shared_from_this)
这是另一个成语,它避免拼写出所有的共享指针。
相反保持spearate共享指针到插座和缓冲区,你让一个类同时包含:
结构CSession:升压:: enable_shared_from_this&LT; CSession&GT; {
CSession(BA :: io_service对象和放大器; iosev)
:m_iosev(iosev),m_sock(m_iosev)
{} 无效do_response(); 私人的:
无效write_handler(错误_ code EC,为size_t bytes_transferred); 巴:: io_service对象和放大器; m_iosev;
TCP ::插座m_sock;
标准::字符串响应;
};
和现在的绑定如下:
的boost ::绑定(安培; CSession :: write_handler,
shared_from_this()/ *保活! * /
巴::占位符::错误,BA ::占位符:: bytes_transferred)
要简单得多。会话管理是有责任的内部CService
,像以前一样:
无效的start()
{
自动会话=提振:: make_shared&LT; CSession&GT;(m_iosev);
m_acceptor.async_accept(会话级&GT; m_sock,
提高::绑定(安培;内部CService :: accept_handler,为此,会议,巴::占位符::错误));
}无效accept_handler(提高:: shared_ptr的&LT; CSession&GT;会话,错误_ code EC){
如果(EC){
的std :: CERR&LT;&LT; 接受失败:&LT;&LT; ec.message()&所述;&下; \\ n;
}其他{
会话级&GT; do_response();
开始();
}
}
同样的 <大骨节病> 住在Coliru 骨节病>
的#include&LT;&iostream的GT;
#包括LT&;串GT;
#包括LT&;升压/ asio.hpp&GT;
#包括LT&;升压/ bind.hpp&GT;
#包括LT&;升压/ make_shared.hpp&GT;
#包括LT&;升压/ enable_shared_from_this.hpp&GT;命名空间BA =的boost :: ASIO;
使用boost ::系统::错误_ code;
使用BA :: IP :: TCP;命名空间的HelloWorld { 结构CSession:升压:: enable_shared_from_this&LT; CSession&GT; {
CSession(BA :: io_service对象和放大器; iosev)
:m_iosev(iosev),m_sock(m_iosev)
{} 无效do_response(){
响应=你好!异步世界\\ n;
性病::法院LT&;&LT; m_sock.remote_endpoint()地址()&所述;&下;的std :: ENDL; m_sock.async_write_some(BA ::缓冲液(响应)
提高::绑定(安培; CSession :: write_handler,
shared_from_this()/ *保活! * /
巴::占位符::错误,BA ::占位符:: bytes_transferred));
} 私人的: 无效write_handler(错误_ code EC,为size_t bytes_transferred)
{
如果(EC)
性病::法院LT&;&LT; 发送失败!&LT;&LT;提高::系统:: SYSTEM_ERROR(EC)。什么()&LT;&LT; \\ n;
其他
性病::法院LT&;&LT;响应&LT;&LT; 已发送(&LT;&LT; bytes_transferred&LT;&LT;传输的字节)\\ n;
} 巴:: io_service对象和放大器; m_iosev; 友元类内部CService;
TCP ::插座m_sock; 标准::字符串响应;
}; 结构内部CService
{
内部CService(BA :: io_service对象和放大器; iosev)
:m_iosev(iosev),m_acceptor(iosev,TCP ::端点(TCP :: V4(),6767))
{} 无效的start(){
自动会话=提振:: make_shared&LT; CSession&GT;(m_iosev);
m_acceptor.async_accept(会话级&GT; m_sock,
提高::绑定(安培;内部CService :: accept_handler,为此,会议,巴::占位符::错误));
} 无效accept_handler(提高:: shared_ptr的&LT; CSession&GT;会话,错误_ code EC){
如果(EC){
的std :: CERR&LT;&LT; 接受失败:&LT;&LT; ec.message()&所述;&下; \\ n;
}其他{
会话级&GT; do_response();
开始();
}
} 私人的:
巴:: io_service对象和放大器; m_iosev;
TCP ::受m_acceptor;
};
}诠释主(){
巴:: io_service对象iosev; 使用命名空间的HelloWorld; 内部CService SEV(iosev);
sev.start();
iosev.run();
}
使用类似的输出。
I am porting an application which uses Boost::Asio to an embedded system.
I have already cross-compiled boost 1.57.0 binaries for the board using its BSP. To test the libraries working, I ran two http server examples that use synchronized and asynchronized writing respectively.
The Sync version runs fine; while the Async one failed at writing. It returned error "Operation canceled".
Can anyone point out where I should look for? Thanks.
/*
* 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;
}
On your async_write_some
call you forget to hold a reference to the socket instance.
This causes the socket
object to be destructed, and as part of the destructor, all pending asynchronous operations are canceled. This explains that you receive ec
operation_aborted
.
Fix it either by adding the socket
pointer to the bound arguments, or alternatively use the enable_shared_from_this
idiom with your CSession
type.
Using more shared_pointer
magic:
Here's the "simplest" edit:
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";
}
Which should be bound like:
psocket->async_write_some(ba::buffer(*pstr),
boost::bind(&CService::write_handler, this, pstr, psocket,
ba::placeholders::error, ba::placeholders::bytes_transferred));
Several style improvements
- not
using namespace
- using the
asio
placeholders (not_1
,_2
)
Prints:
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)
...
Using CSession
(enable_shared_from_this)
This is the other idiom, and it avoid spelling out all the shared-pointers.
Instead of keeping spearate shared pointers to the socket and buffer, you make a class to contain both:
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;
};
And now the bind looks like:
boost::bind(&CSession::write_handler,
shared_from_this(), /* keep-alive! */
ba::placeholders::error, ba::placeholders::bytes_transferred)
Much simpler. Session management is the responsibility of the CService
, like before:
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();
}
}
Again 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();
}
With similar output.
这篇关于的boost ::短耳异步写入失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!