boost :: async_write вызывает ошибку. Существующее соединение было принудительно закрыто удаленным хостом. - PullRequest
0 голосов
/ 27 марта 2020

Я хочу отправить структуру с клиента на сервер, используя boost::asio. Я перешел по ссылке учебника повышения https://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/examples.html#boost_asio .examples.serialization . Я немного изменил код в server.cpp и client.cpp. С новым кодом, после установления соединения, client.cpp записывает структуру акций на сервер и считывает информацию о запасах на стороне сервера. (В учебной версии, после того, как соединение установлено, сервер записывает стандартную структуру клиенту, а клиент читает их. Эта версия работает для меня.)

Моя проблема в том, что после установления соединения async_write в client.cpp вызывает ошибку

Error in write: An existing connection was forcibly closed by the remote host

, а async_read в server.cpp вызывает ошибку

Error in read:The network connection was aborted by the local system.

Как подсказывают некоторые ответы на форумах, я изменил this указатели в обработчиках функций async_write и async_read на shared_from_this. Тем не менее проблема существует.

Я не могу определить, вызывает ли проблема сторона клиента или сервера. Пожалуйста, помогите.

сервер. cpp

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <vector>
#include "connection.h" // Must come before boost/serialization headers.
#include <boost/serialization/vector.hpp>
#include <boost/enable_shared_from_this.hpp>
#include "stock.h"

namespace s11n_example
{
    /// Serves stock quote information to any client that connects to it.
    class server : public boost::enable_shared_from_this<server>
    {
        private:
            /// The acceptor object used to accept incoming socket connections.
            boost::asio::ip::tcp::acceptor acceptor_;
            /// The data to be sent to each client.
            std::vector<stock> stocks_;

        public:
            /// Constructor opens the acceptor and starts waiting for the first incoming
            /// connection.
            server(boost::asio::io_service& io_service, unsigned short port):
            acceptor_(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
            {
                // Start an accept operation for a new connection.
                connection_ptr new_conn(new connection(acceptor_.get_io_service()));
                acceptor_.async_accept(new_conn->socket(),
                    boost::bind(&server::handle_accept, this,boost::asio::placeholders::error, new_conn));
            }

            /// Handle completion of a accept operation.
            void handle_accept(const boost::system::error_code& e, connection_ptr conn)
            {
                if (!e)
                {
                    std::cout <<  "Received a connection" <<std::endl;
                    conn->async_read(stocks_,
                         boost::bind(&server::handle_read, shared_from_this(),boost::asio::placeholders::error));
                }
                // Start an accept operation for a new connection.
                connection_ptr new_conn(new connection(acceptor_.get_io_service()));
                acceptor_.async_accept(new_conn->socket(),
                    boost::bind(&server::handle_accept, this,boost::asio::placeholders::error, new_conn));
            }
            /// Handle completion of a read operation.
            void handle_read(const boost::system::error_code& e)
            {
                if (!e)
                {
                    // Print out the data that was received.
                    for (std::size_t i = 0; i < stocks_.size(); ++i)
                    {
                        std::cout << "Stock number " << i << "\n";
                        std::cout << "  code: " << stocks_[i].code << "\n";
                        std::cout << "  name: " << stocks_[i].name << "\n";
                        std::cout << "  open_price: " << stocks_[i].open_price << "\n";
                        std::cout << "  high_price: " << stocks_[i].high_price << "\n";
                        std::cout << "  low_price: " << stocks_[i].low_price << "\n";
                        std::cout << "  last_price: " << stocks_[i].last_price << "\n";
                        std::cout << "  buy_price: " << stocks_[i].buy_price << "\n";
                        std::cout << "  buy_quantity: " << stocks_[i].buy_quantity << "\n";
                        std::cout << "  sell_price: " << stocks_[i].sell_price << "\n";
                        std::cout << "  sell_quantity: " << stocks_[i].sell_quantity << "\n";
                    }
                }
                else
                {
                    // An error occurred.
                    std::cerr << "Error in read:" << e.message() << std::endl;
                }
            }
    };

} // namespace s11n_example
int main(int argc, char* argv[])
{
    try
    {
        // Check command line arguments.
        if (argc != 2)
        {
            std::cerr << "Usage: server <port>" << std::endl;
            return 1;
        }
        unsigned short port = boost::lexical_cast<unsigned short>(argv[1]);

        boost::asio::io_service io_service;
        boost::shared_ptr<s11n_example::server> server(new s11n_example::server(io_service, port));
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

клиент. cpp

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include "connection.h" // Must come before boost/serialization headers.
#include <boost/serialization/vector.hpp>
#include  <boost/enable_shared_from_this.hpp>
#include "stock.h"

namespace s11n_example {

    /// Downloads stock quote information from a server.
    class client : public boost::enable_shared_from_this<client>
    {
        private:
            /// The connection to the server.
            connection connection_;
            /// The data received from the server.
            std::vector<stock> stocks_;

        public:
            /// Constructor starts the asynchronous connect operation.
            client(boost::asio::io_service& io_service, const std::string& host, const std::string& service)
            : connection_(io_service)
            {
                // Resolve the host name into an IP address.
                boost::asio::ip::tcp::resolver resolver(io_service);
                boost::asio::ip::tcp::resolver::query query(host, service);
                boost::asio::ip::tcp::resolver::iterator endpoint_iterator =
                resolver.resolve(query);
                // Start an asynchronous connect operation.
                boost::asio::async_connect(connection_.socket(), endpoint_iterator,
                    boost::bind(&client::handle_connect, this,boost::asio::placeholders::error));
            }
            /// Handle completion of a connect operation.
            void handle_connect(const boost::system::error_code& e) //, connection_ptr conn
            {
                if (!e)
                {
                    std::cout << "Connected to server!" << std::endl;
                    // Create the data to be sent to each client.
                    stock s;
                    s.code = "ABC";
                    s.name = "A Big Company";
                    s.open_price = 4.56;
                    s.high_price = 5.12;
                    s.low_price = 4.33;
                    s.last_price = 4.98;
                    s.buy_price = 4.96;
                    s.buy_quantity = 1000;
                    s.sell_price = 4.99;
                    s.sell_quantity = 2000;
                    stocks_.push_back(s);

                    s.code = "DEF";
                    s.name = "Developer Entertainment Firm";
                    s.open_price = 20.24;
                    s.high_price = 22.88;
                    s.low_price = 19.50;
                    s.last_price = 19.76;
                    s.buy_price = 19.72;
                    s.buy_quantity = 34000;
                    s.sell_price = 19.85;
                    s.sell_quantity = 45000;
                    stocks_.push_back(s);

                    // Successfully established connection. Start operation to write the list
                    // of stocks.
                    connection_.async_write(stocks_,
                    boost::bind(&client::handle_write, shared_from_this(),boost::asio::placeholders::error)); //,&conn )
                }
                else
                {
                      // An error occurred. Log it and return.
                      std::cerr << "Error in connecting to server" << e.message() << std::endl;
                }
            }

            /// Handle completion of a write operation.
            void handle_write(const boost::system::error_code& e)//, connection* conn
            {
                if (!e)
                {
                    std::cout << "Finished writing to server" << std::endl;
                }
                else
                {
                  // An error occurred. Log it and return. Since we are not starting a new
                  // operation the io_service will run out of work to do and the client will
                  // exit.
                  std::cerr << "Error in write: " << e.message() << std::endl;
                }

                // Nothing to do. The socket will be closed automatically when the last
                // reference to the connection object goes away.
            }
    };

} // namespace s11n_example

int main(int argc, char* argv[])
{
    try
    {
        // Check command line arguments.
        if (argc != 3)
        {
            std::cerr << "Usage: client <host> <port>" << std::endl;
            return 1;
        }

        boost::asio::io_service io_service;
        //s11n_example::client client(io_service, argv[1], argv[2]);
        boost::shared_ptr<s11n_example::client> client(new s11n_example::client(io_service, argv[1], argv[2]));
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

Спасибо.

1 Ответ

1 голос
/ 27 марта 2020

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

conn->async_read(stocks_,
     boost::bind(&server::handle_read, shared_from_this(), conn, boost::asio::placeholders::error));

Лямбды облегчают чтение, чем использование bind:

auto self = shared_from_this();
conn->async_read(stocks_,
[self, this, conn] (boost::system::error_code ec) { handle_read(ec); });

Переменные, перечисленные в список захвата будет скопирован, поэтому общие указатели будут сохранены.

...