Ошибка сегментации акцептора сокета Boost

Я пытаюсь написать tcp-сервер. Из ссылки руководства по продвижению введите описание ссылки здесь. Когда я пытаюсь открыть акцептор - segmentation fault, IDE показывает мне эту строку object_pool_access::prev(live_list_) = o; Что я делаю неправильно? Я пытаюсь по-другому, например, запускать потоки для контекста, но это не работает. Иногда, когда я пытаюсь исправить, я получаю это сообщение -

tpp.c:82: __pthread_tpp_change_priority: Assertion `new_prio == -1 || (new_prio >= fifo_min_prio && new_prio <= fifo_max_prio)' failed.
Aborted (core dumped)

Код содержится в 1-м файле. Класс приложения с io_context, он здесь, потому что я буду использовать его в других частях программы:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <memory>

using namespace boost::asio;

class api_application
{
public:
    virtual ~api_application() {}

    virtual void start() = 0;
    virtual boost::asio::io_context& get_context() = 0;
};

class application : public api_application
{
public:
    application();
    ~application() override {}

public:
    virtual void start() override;
    virtual boost::asio::io_context& get_context() override;
    
    void stop();

private:
    boost::asio::io_context _context;

    std::shared_ptr<tcp_server> _server;
};


application::application()
:   
_context(),
_server(std::make_shared<tcp_server>(*this))
{}

void application::start()
{
    _server->start();
    _context.run();
}

void application::stop()
{
    _context.stop();
}

boost::asio::io_context& application::get_context()
{
    return _context;
}

Сетевой код со строкой ошибки:

class connection : public std::enable_shared_from_this<connection>
{
public:
    typedef std::shared_ptr<connection> con_ptr;

    static con_ptr create(boost::asio::io_context& io_service)
    {
        return con_ptr(new connection(io_service));
    }

    ip::tcp::socket& socket();
    void send(std::string message);

private:
    connection(boost::asio::io_context& io_service);

    void handle_write(const boost::system::error_code& err, size_t s);

private:
    ip::tcp::socket _socket;
};

class tcp_server
{
public:
    tcp_server(api_application& app);

    void start();
private:
    void start_accept();
    void handle_accept(connection::con_ptr new_connection, const boost::system::error_code& error);

    api_application&   _app;
    ip::tcp::endpoint       _endpoint;
    ip::tcp::acceptor       _acceptor;
};


tcp_server::tcp_server(api_application& app)
:
_app(app), 
_endpoint(boost::asio::ip::address_v4::any(), 80),
_acceptor(app.get_context())
{}

void tcp_server::start()
{
    if (_acceptor.is_open())
        return;
    
    _acceptor.open(_endpoint.protocol()); // Here segfault
    _acceptor.set_option(ip::tcp::socket::reuse_address(true));
    
    _acceptor.bind(_endpoint);
    _acceptor.listen();
    start_accept();
}

void tcp_server::start_accept()
{
    connection::con_ptr new_connection =
    connection::create((boost::asio::io_context&)_acceptor.get_executor().context());

    _acceptor.async_accept(new_connection->socket(),
        boost::bind(&tcp_server::handle_accept, this, new_connection,
        boost::asio::placeholders::error));
}

void tcp_server::handle_accept(connection::con_ptr new_connection, const boost::system::error_code& error)
{
    if (!error)
    {
        new_connection->send("Success connection");
    }

    start_accept();
}

void connection::send(std::string message)
{
    boost::asio::async_write(_socket, boost::asio::buffer(message),
        boost::bind(&connection::handle_write, shared_from_this(),
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));
}

connection::connection(boost::asio::io_context& io_service)
: _socket(io_service)
{}

int main(int argc, const char** argv)
{
    application app();
    app.start();
    return 0;
}

минимальный воспроизводимый пример должен быть компилируемым, т.е. содержать все необходимые #include операторы.

273K 03.01.2023 06:32

Добавлено включает.

lbsmart 03.01.2023 13:16

@lbsmart по-прежнему не может скомпилироваться, так как ваш основной файл начинается с самого неприятного синтаксического анализа.

sehe 03.01.2023 18:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я обнаружил вероятную проблему при переписывании кода, чтобы избежать контекстных ссылок. См. Обновление

У меня нет проблем с кодом, представляющим недостающие биты:

Прямой эфир на Колиру

#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <memory>

namespace asio = boost::asio;
using asio::ip::tcp;
using boost::system::error_code;

class connection : public std::enable_shared_from_this<connection> {
  public:
    typedef std::shared_ptr<connection> con_ptr;

    static con_ptr create(asio::io_context& io_service) {
        return con_ptr{new connection(io_service)};
    }

    tcp::socket& socket() { return _socket; }
    void         send(std::string message);

  private:
    connection(asio::io_context& io_service);

    void handle_write(error_code err, size_t s) {
        std::cerr << "handle_write: " << err.message() << " " << s << std::endl;
    }

  private:
    tcp::socket _socket;
};

struct api_application {
    virtual ~api_application() {}
    virtual void              start()       = 0;
    virtual asio::io_context& get_context() = 0;
};

class tcp_server {
  public:
    tcp_server(api_application& app);

    void start();

  private:
    void start_accept();
    void handle_accept(connection::con_ptr new_connection,
                       error_code          error);

    api_application& _app;
    tcp::endpoint    _endpoint;
    tcp::acceptor    _acceptor;
};

class application : public api_application {
  public:
    application();
    ~application() override {}

  public:
    virtual void              start() override;
    virtual asio::io_context& get_context() override;

    void stop();

  private:
    asio::io_context _context;

    std::shared_ptr<tcp_server> _server;
};

application::application()
    : _context()
    , _server(std::make_shared<tcp_server>(*this)) {}

void application::start() {
    _server->start();
    _context.run();
}

tcp_server::tcp_server(api_application& app)
    : _app(app)
    , _endpoint({}, 8989)
    , _acceptor(app.get_context()) {}

void tcp_server::start() {
    if (_acceptor.is_open())
        return;

    _acceptor.open(_endpoint.protocol()); // Here segfault
    _acceptor.set_option(tcp::acceptor::reuse_address(true));

    _acceptor.bind(_endpoint);
    _acceptor.listen();
    start_accept();
}

void tcp_server::start_accept() {
    connection::con_ptr new_connection = connection::create(
        (asio::io_context&)_acceptor.get_executor().context());

    _acceptor.async_accept(new_connection->socket(),
                           boost::bind(&tcp_server::handle_accept, this,
                                       new_connection,
                                       asio::placeholders::error));
}

void tcp_server::handle_accept(connection::con_ptr new_connection,
                               error_code          error) {
    if (!error) {
        new_connection->send("Success connection");
    }

    start_accept();
}

void connection::send(std::string message) {
    async_write(_socket, asio::buffer(message),
                boost::bind(&connection::handle_write,
                            shared_from_this(),
                            asio::placeholders::error,
                            asio::placeholders::bytes_transferred));
}

connection::connection(asio::io_context& io_service)
    : _socket(io_service) {}

void application::stop() { _context.stop(); }

asio::io_context& application::get_context() { return _context; }

int main() {
    application app;
    app.start();
}

Отпечатки, например.

g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp
./a.out&
for a in {1..10}; do sleep 0.5; nc 127.0.0.1 8989 <<<"Hello world"; done
kill %1
Success connectionhandle_write: Success 18
handle_write: Success connectionSuccess 18
handle_write: Success Success connection18
Success connectionhandle_write: Success 18
Success connectionhandle_write: Success 18
Success connectionhandle_write: Success 18
Success connectionhandle_write: Success 18
Success connectionhandle_write: Success 18
Success connectionhandle_write: Success 18
Success connectionhandle_write: Success 18

Резюме

Ваша проблема в другом. Разрешения, обработка исключений, ODR, возможно, вы используете не тот код, о котором думаете.

Кроме того, этот код кажется излишне сложным и немного устаревшим (io_service устарел уже довольно давно).

ОБНОВЛЯТЬ

Это очень подозрительный код

соединение::con_ptr новое_соединение = соединение::создать( (asio::io_context&)_acceptor.get_executor().context());

Если это работает, это связано с недокументированными деталями реализации. Технически это Undefined Behavior, потому что он выполняет жесткую повторную интерпретацию. Вместо этого просто используйте исполнителя по назначению!

auto new_connection = connection::create(_acceptor.get_executor());

Здесь все переработано, чтобы избежать контекстных ссылок:

#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <memory>

namespace asio = boost::asio;
using asio::ip::tcp;
using boost::system::error_code;

class connection : public std::enable_shared_from_this<connection> {
  public:
    typedef std::shared_ptr<connection> con_ptr;

    static con_ptr create(asio::any_io_executor ex) {
        return con_ptr{new connection(ex)};
    }

    tcp::socket& socket() { return _socket; }
    void         send(std::string message);

  private:
    connection(asio::any_io_executor ex);

    void handle_write(error_code err, size_t s) {
        std::cerr << "handle_write: " << err.message() << " " << s << std::endl;
    }

  private:
    tcp::socket _socket;
};

struct api_application {
    virtual ~api_application() {}
    virtual void                  start()        = 0;
    virtual asio::any_io_executor get_executor() = 0;
};

class tcp_server {
  public:
    tcp_server(api_application& app);

    void start();

  private:
    void start_accept();
    void handle_accept(connection::con_ptr new_connection,
                       error_code          error);

    api_application& _app;
    tcp::endpoint    _endpoint;
    tcp::acceptor    _acceptor;
};

class application : public api_application {
  public:
    application();
    ~application() override {}

  public:
    virtual void                  start() override;
    virtual asio::any_io_executor get_executor() override;

    void stop();

  private:
    asio::io_context _context;

    std::shared_ptr<tcp_server> _server;
};

application::application()
    : _context()
    , _server(std::make_shared<tcp_server>(*this)) {}

void application::start() {
    _server->start();
    _context.run();
}

tcp_server::tcp_server(api_application& app)
    : _app(app)
    , _endpoint({}, 8989)
    , _acceptor(app.get_executor()) {}

void tcp_server::start() {
    if (_acceptor.is_open())
        return;

    _acceptor.open(_endpoint.protocol()); // Here segfault
    _acceptor.set_option(tcp::acceptor::reuse_address(true));

    _acceptor.bind(_endpoint);
    _acceptor.listen();
    start_accept();
}

void tcp_server::start_accept() {
    auto new_connection = connection::create(_acceptor.get_executor());

    _acceptor.async_accept(new_connection->socket(),
                           boost::bind(&tcp_server::handle_accept, this,
                                       new_connection,
                                       asio::placeholders::error));
}

void tcp_server::handle_accept(connection::con_ptr new_connection,
                               error_code          error) {
    if (!error) {
        new_connection->send("Success connection");
    }

    start_accept();
}

void connection::send(std::string message) {
    async_write(_socket, asio::buffer(message),
                boost::bind(&connection::handle_write,
                            shared_from_this(),
                            asio::placeholders::error,
                            asio::placeholders::bytes_transferred));
}

connection::connection(asio::any_io_executor ex) : _socket(ex) {}

void application::stop() { _context.stop(); }
asio::any_io_executor application::get_executor() {
    return _context.get_executor();
}

int main() {
    application app;
    app.start();
}

Все так же печатаю Live On Coliru

Я обнаружил вероятную проблему при переписывании кода, чтобы избежать контекстных ссылок. См. Обновление

sehe 03.01.2023 19:10

Другие вопросы по теме