Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost asio getting `Error Code : 125 Operation cancelled` [closed]

I was just trying to accept incoming request with acceptor socket and when it enters the async_accept it throws out an error, I'm not sure what is causing the error. The thing is I'm not even sending the request from the client but still it enters the async_accept handler for some reason, here is the part of the code which is causing the error

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();
}

server.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);
        });
    }

};

connection.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;
                    }
                });
            }
        }
};

error.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;
    }
}

Any help on this would be appreciated. Thanks!

The error lies in having the io_thread_.run() in the destructor which would destroy the socket object by then

like image 467
Bad_Panda Avatar asked Jul 13 '26 18:07

Bad_Panda


1 Answers

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

    server->start();
}

server will call the deleter, which destroys Server_ on exiting main. You Would like to join any threads or await the shutdown of the server before exiting main.

You would in your case join the iothread, like you TRIED to do.

However, you do it in the server constructor:

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();
}

I can't really figure out how this would not hang indefinitely due to the work_. On tangentially related observation is that work_ is NOT initilaized before ioc_ (or thread_) because initialization happens in order of member declaration instead of order in which the initializers appear. You will want to fix the declaration order regardless:

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_;

Similarly in 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_;

Fixed Demo

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
}

This would give 4s for the first client to connect, and will shut down as soon as all connections are done.

like image 160
sehe Avatar answered Jul 15 '26 09:07

sehe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!