Сломанная труба после записи в сокет - PullRequest
0 голосов
/ 26 февраля 2019

В моей сетевой библиотеке я могу выполнять асинхронную запись в сеть, если я run() и restart() io_context вручную.

Я сейчас пытаюсь изменить масштаб, добавив пул потоков:

.hpp

struct pool : public std::enable_shared_from_this<pool> {
  pool(const pool &) = delete;
  auto operator=(const pool &) -> pool & = delete;
  explicit pool(pool_parameters config, db_parameters params) noexcept;

  asio::io_context m_io_context;

  asio::thread_pool m_workers;

  asio::executor_work_guard<asio::io_context::executor_type> m_work_guard;

  /// \brief Container to hold connections.
  std::vector<std::unique_ptr<dbc::connection>> m_connections;
};

.cpp

pool::pool(pool_parameters config, db_parameters params) noexcept
    : m_config{std::move(config)},
      m_params{std::move(params)},
      m_work_guard{asio::make_work_guard(m_io_context)},
      m_workers{m_config.thread_pool_size} {
  m_connections.reserve(m_config.connection_pool_size);
  asio::post(m_workers, [&]() { m_io_context.run(); });
}

, который управляет соединениями:

.hpp

struct abstract_connection : connection {
  explicit abstract_connection(const std::shared_ptr<pool> &pool) noexcept;

  ~abstract_connection() override;
      packet m_buffer;

      asio::local::stream_protocol::endpoint m_endpoint;

      asio::generic::stream_protocol::socket m_socket;

      asio::io_context::strand m_strand;
    };

.cpp

abstract_connection::abstract_connection(const std::shared_ptr<pool> &pool) noexcept
        : m_params{pool->m_params},
          m_config{pool->m_config},
          m_endpoint{pool->m_config.socket},
          m_socket{pool->m_io_context},
          m_strand{pool->m_io_context} {
      m_socket.connect(m_endpoint);
      m_socket.non_blocking(true);
    }

abstract_connection::~abstract_connection() {
      std::error_code ec;
      m_socket.shutdown(asio::generic::stream_protocol::socket::shutdown_both, ec);
      m_socket.close();
    }

Теперь прибывает запутанный парк.На ctor конкретного объекта соединения мне нужно сделать рукопожатие вместе с рукопожатием деструктора того же класса.Что не происходит, потому что объект сокета ведет себя странным образом:

Если я отправляю данные асинхронно, в сокет ничего не записывается, и иногда я получаю сообщение об ошибке сломанного канала:

asio::dispatch(m_strand, [&]() {
          m_buffer = write::startup(m_params);
          asio::async_write(m_socket, asio::buffer(m_buffer), [](std::error_code ec, std::size_t len) {});
        });

Если я выполняю синхронную запись, я получаю сообщение об ошибке прерванного канала, прежде чем я смогу читать из сокета:

std::error_code ec;
        auto startup = write::startup(m_params);
        asio::write(m_socket, asio::buffer(startup), ec);
        if (set_error(ec)) {
          std::cerr << " XXX " << ec.message() << std::endl;
          return;
        }

        m_buffer.reserve(327);
        asio::read(m_socket, asio::buffer(m_buffer), ec);
        std::cerr << ec.message() << std::endl;
        std::cerr << m_buffer.size() << std::endl;

Соединение выполняется через сокет Unix, и между ними сидит socat, поэтому яможет видеть данные, приходящие и уходящие вместе с сообщениями о сломанной трубе.Попытка подключиться к удаленному устройству с помощью стороннего инструмента работает, все соответствующие данные отображаются в socat, поэтому я считаю, что проблема в моем коде.

Как я могу отладить то, что происходит с сокетом?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Я решил проблему, сделав блокировку сокета (non_blocking(false)), о которой я бы не подумал без ответа Superlokkus.

0 голосов
/ 26 февраля 2019

Судя по опубликованному вами коду, ваш boost::asio::thread_pool просто выходит за рамки раннего.Ваш abstract_connection класс просто принимает const std::shared_ptr<pool> &pool, что означает, что ваши абстрактные экземпляры соединений не содержат счетчика ссылок в вашем пуле потоков.Ссылки на std::shared_ptr вообще не имеют смысла, поэтому ваш abstract_connection просто возьмет std::shared_ptr<const pool> pool в своем конструкторе, который вы должны скопировать или переместить в элемент с тем же типом.

...