的boost ::短耳异步写入失败 [英] Boost::Asio Async write failed

查看:182
本文介绍了的boost ::短耳异步写入失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我端起它使用的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));

Live On Coliru

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆