Boost asio 获取“错误代码:125 操作已取消”[关闭]

Posted

技术标签:

【中文标题】Boost asio 获取“错误代码:125 操作已取消”[关闭]【英文标题】:Boost asio getting `Error Code : 125 Operation cancelled` [closed] 【发布时间】:2021-02-09 06:15:44 【问题描述】:

我只是试图用 acceptor socket 接受传入的请求,当它进入 async_accept 时会抛出一个错误,我不确定是什么导致了错误.问题是我什至没有从客户端发送请求,但由于某种原因它仍然进入 async_accept 处理程序,这是导致错误的代码部分

main.cpp

#include <iostream>


#include "server.hpp"
#include "connection.hpp"

class Connection;

int main()
    using Server_ = Server<Connection>;
    auto server = std::make_unique<Server_>(8989);

    server->start();

服务器.hpp

#pragma once

#include <thread>

#include <boost/asio.hpp>

template <typename Connection> 
class Server
    using shared_connection = std::shared_ptr<Connection>; 

    private:
    unsigned short port_;
    std::thread io_thread_;
    boost::asio::io_context ioc_;
    boost::asio::io_context::work work_;
    boost::asio::ip::tcp::endpoint endpoint_;
    boost::asio::ip::tcp::acceptor acceptor_;

    void handle_new_request(shared_connection connection, const system::error_code &ec)
        if(!ec)
            connection->start_operation();
        else
            error::print(ec);
            return;
        
    

    public:
    explicit Server(unsigned short port)
    : acceptor_(ioc_)
    , work_(ioc_)
    , port_(port)
    , endpoint_(asio::ip::tcp::v4(), port)  
        io_thread_ = std::move(std::thread([&] ioc_.run(); ));
        io_thread_.join();
    
    
    ~Server()  
        if(acceptor_.is_open()) 
            acceptor_.close(); 
        io_thread_.join();
    

    void start()
        using namespace asio::ip;

        system::error_code ec;

        // creates an actual operating system socket
        acceptor_.open(endpoint_.protocol(),ec); 
        acceptor_.set_option(tcp::acceptor::reuse_address(true),ec);
        // binds to the endpoint
        acceptor_.bind(endpoint_,ec); 

        if(!ec)
            std::cout << "Listening for requests from port " << port_ << std::endl;
            acceptor_.listen();
        else
            error::print(ec);
            return;
        

        shared_connection connection = std::make_shared<Connection>(ioc_);
        acceptor_.async_accept(connection->sock_,[=](system::error_code ec)
            handle_new_request(connection,ec);
        );
    

;

连接.hpp

#pragma once

#include <memory>

#include <boost/asio.hpp>

class Connection : public std::enable_shared_from_this<Connection> 
    using shared_connection = std::shared_ptr<Connection>;
        std::vector<char> buffer_space_;
    private:
        boost::asio::mutable_buffers_1 buffer_;
        boost::asio::io_context& ioc_;
    public:
        boost::asio::ip::tcp::socket sock_;

        explicit Connection(boost::asio::io_context &context,const int &size = 1024)
            : ioc_(context)
            , sock_(context)
            , buffer_space_(size) 
            , buffer_(buffer_space_.data(),size)
        
        ~Connection() if(sock_.is_open()) sock_.close(); 
        void start_operation()
            if(sock_.is_open())
                sock_.async_read_some(buffer_,[me = shared_from_this()](const system::error_code &ec, std::size_t bytes)
                    if(!ec)
                        for(int i=0;i<bytes;++i)
                            std::cout << me->buffer_space_[i];
                        std::cout << std::endl;
                        me->start_operation();
                    else
                        error::print(ec);
                        return;
                    
                );
            
        
;

错误.hpp

#pragma once

#include <iostream>

#include <boost/system/error_code.hpp>

namespace error 
    inline void print(const boost::system::error_code &ec)
        std::cerr << "Error Code : " << ec.value() << ", Message : " << ec.message() << std::endl;
    

对此的任何帮助将不胜感激。谢谢!

错误在于析构函数中有io_thread_.run(),这会破坏套接字对象

【问题讨论】:

请提供minimal reproducible example 猜测接受器正在关闭,这会导致挂起的async_accept 被取消 @AlanBirtles 是的,我已经进行了必要的更改。如果接收器正在关闭,则意味着拥有它的服务器对象正在被销毁我认为不是这种情况,因为服务器对象的析构函数具有 io_thread_.join() @Bad_Panda 您的服务器实例在 main() 退出时被销毁。无需通过您的代码,这将取消所有未完成的操作,然后可以从析构函数中加入线程。 @janm 是的,我刚刚意识到,非常感谢您的帮助! 【参考方案1】:
int main()
    using Server_ = Server<Connection>;
    auto server = std::make_unique<Server_>(8989);

    server->start();

server 将调用删除器,它会在退出 main 时销毁 Server_。您想在退出 main 之前加入任何线程或等待服务器关闭。

在你的情况下,你会加入 iothread,就像你尝试做的那样。

但是,您可以在服务器构造函数中执行此操作:

explicit Server(unsigned short port)
    : acceptor_(ioc_)
    , work_(ioc_)
    , port_(port)
    , endpoint_(asio::ip::tcp::v4(), port)

    io_thread_ = std::move(std::thread([&]  ioc_.run(); ));
    io_thread_.join();

我真的不知道这怎么不会因为工作而无限期挂起_。与切线相关的观察是work_ 没有在ioc_(或thread_)之前初始化,因为初始化是按照成员声明的顺序而不是初始化程序出现的顺序发生的。无论如何,您都需要修正申报顺序:

boost::asio::io_context ioc_;
boost::asio::ip::tcp::acceptor acceptor_;
boost::asio::io_context::work work_;
unsigned short port_;
boost::asio::ip::tcp::endpoint endpoint_;
std::thread io_thread_;

同样在Connection:

  private:
    boost::asio::io_context& ioc_;

  public:
    boost::asio::ip::tcp::socket sock_;

  private:
    std::vector<char> buffer_space_;
    boost::asio::mutable_buffers_1 buffer_;

固定演示

Live On Coliru

#include <iostream>

#include <boost/system/error_code.hpp>

namespace error 
    inline void print(const boost::system::error_code& ec)
    
        std::cerr << "Error Code : " << ec.value()
                  << ", Message : " << ec.message() << std::endl;
    


#include <memory>

#include <boost/asio.hpp>

class Connection : public std::enable_shared_from_this<Connection> 
    using shared_connection = std::shared_ptr<Connection>;

  private:
    boost::asio::io_context& ioc_;

  public:
    boost::asio::ip::tcp::socket sock_;

  private:
    std::vector<char> buffer_space_;
    boost::asio::mutable_buffers_1 buffer_;

  public:
    explicit Connection(
        boost::asio::io_context& context, const int& size = 1024)
        : ioc_(context)
        , sock_(context)
        , buffer_space_(size)
        , buffer_(buffer_space_.data(), size)
    
    

    void start_operation()
    
        if (sock_.is_open()) 
            sock_.async_read_some(buffer_,
                [me = shared_from_this()](
                    const boost::system::error_code& ec, std::size_t bytes) 
                    if (!ec) 
                        for (size_t i = 0; i < bytes; ++i) 
                            std::cout << me->buffer_space_[i];
                        
                        std::cout << std::endl;
                        me->start_operation();
                     else 
                        error::print(ec);
                        return;
                    
                );
        
    
;
#include <thread>

#include <boost/asio.hpp>

template <typename Connection> class Server 
    using shared_connection = std::shared_ptr<Connection>;

  private:
    boost::asio::io_context ioc_;
    boost::asio::ip::tcp::acceptor acceptor_;
    boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
        work_ ioc_.get_executor();
    uint16_t port_;
    boost::asio::ip::tcp::endpoint endpoint_;
    std::thread io_thread_;

    void handle_new_request(
        shared_connection connection, const boost::system::error_code& ec)
    
        if (!ec) 
            connection->start_operation();
         else 
            error::print(ec);
            return;
        
    

  public:
    explicit Server(uint16_t port)
        : acceptor_(ioc_)
        , port_(port)
        , endpoint_(boost::asio::ip::tcp::v4(), port)
        , io_thread_([&]  ioc_.run(); )
     ; 

    ~Server()
    
        if (acceptor_.is_open()) 
            boost::system::error_code ec;
            acceptor_.cancel(ec);
            //acceptor_.close(ec);
        
        work_.reset();
        io_thread_.join();
    

    void start()
    
        using boost::asio::ip::tcp;

        boost::system::error_code ec;

        // creates an actual operating system socket
        acceptor_.open(endpoint_.protocol(), ec);
        acceptor_.set_option(tcp::acceptor::reuse_address(true), ec);
        // binds to the endpoint
        acceptor_.bind(endpoint_, ec);

        if (!ec) 
            std::cout << "Listening for requests from port " << port_
                      << std::endl;
            acceptor_.listen();
         else 
            error::print(ec);
            return;
        

        shared_connection connection = std::make_shared<Connection>(ioc_);
        acceptor_.async_accept(
            connection->sock_, [=, this](boost::system::error_code ec) 
                handle_new_request(connection, ec);
            );
    
;

#include <iostream>

//#include "server.hpp"
//#include "connection.hpp"
using namespace std::chrono_literals;

class Connection;

int main()

    using Server_ = Server<Connection>;
    auto server = std::make_unique<Server_>(8989);

    server->start();

    std::this_thread::sleep_for(4s);
    // destructor joins

这将为第一个客户端连接提供 4 秒的时间,并在所有连接完成后立即关闭。

【讨论】:

以上是关于Boost asio 获取“错误代码:125 操作已取消”[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

使用 boost::asio 获取广播源 IP 地址

使用 boost::asio 获取 UDP 套接字远程地址

如何使用boost asio stable timer expiry获取执行时间点

使用boost asio获取网页

如何获取 boost::asio::ip::tcp::socket 的 IP 地址?

使用 boost-asio 时实时将缓冲区写入磁盘