Я пытаюсь написать 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;
}
Добавлено включает.
@lbsmart по-прежнему не может скомпилироваться, так как ваш основной файл начинается с самого неприятного синтаксического анализа.
Я обнаружил вероятную проблему при переписывании кода, чтобы избежать контекстных ссылок. См. Обновление
У меня нет проблем с кодом, представляющим недостающие биты:
#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
Я обнаружил вероятную проблему при переписывании кода, чтобы избежать контекстных ссылок. См. Обновление
минимальный воспроизводимый пример должен быть компилируемым, т.е. содержать все необходимые
#include
операторы.