其他分享
首页 > 其他分享> > c-Boost :: Asio异步写入失败

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

作者:互联网

我正在将使用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调用上,您忘记保存对套接字实例的引用.

这将导致套接字对象被破坏,并且作为析构函数的一部分,所有挂起的异步操作都将被取消.这说明您收到ec operation_aborted.

通过将套接字指针添加到绑定的参数来修复它,或者将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";
}

应该绑定如下:

    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

几项风格改进

>不使用名称空间
>使用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();
    }
}

再次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,asynchronous,boost,boost-asio
来源: https://codeday.me/bug/20191012/1898913.html