boost / asio: очень простой чат-сервер не может получить доступ к полученным сообщениям - PullRequest
0 голосов
/ 14 марта 2019

Я узнал о boost и возился с его сервером и клиентом, чтобы сделать простой чат-сервер, на котором все, что отправляет клиент, просто отображается на сервере.Сам сервер ничего не отправляет и запускает принимающую часть.Это довольно просто.

Код сервера:

#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>

class Server
{
private :
    boost::asio::ip::tcp::socket server_socket;
    boost::asio::ip::tcp::endpoint server_endpoint;
    boost::asio::ip::tcp::acceptor acceptor;
    std::string msg;

public :
    Server(boost::asio::io_context &io) :
    server_socket(io),
    server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015),
    acceptor(io, server_endpoint)
    {
        acceptor.async_accept(server_socket,
            boost::bind(&Server::async_acceptor_handler, this,
                boost::asio::placeholders::error));
    }

    void async_acceptor_handler(const boost::system::error_code &ec)
    {
        if (!ec)
        {
            std::cout << "One client connected...\n";

            server_socket.async_read_some(boost::asio::buffer(msg),
                boost::bind(&Server::async_read_some_handler, this, 
                    boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
            std::cout << "Error description : " << ec.message() << std::endl;
        }
    }

    void async_read_some_handler(const boost::system::error_code &ec)
    {
        if (!ec)
        {
            std::cout << msg << std::endl;

            server_socket.async_read_some(boost::asio::buffer(msg),
                boost::bind(&Server::async_read_some_handler, this, 
                    boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
            std::cout << "Error description : " << ec.message() << std::endl;
        }
    }
};

int main()
{
    boost::asio::io_context io;
    Server s(io);

    io.run();
    return 0;
}

В клиентской части, это снова довольно простой код, просто подключается к серверу и начинает принимать входные данные отпользователь и отправляет на сервер.

Код клиента:

#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>

class Client
{
private :
    boost::asio::ip::tcp::socket client_socket;
    boost::asio::ip::tcp::endpoint server_endpoint;
    std::string msg;

public :
    Client(boost::asio::io_context &iocontext) :
        client_socket(iocontext),
        server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015)
    {
        //connect to server endpoint
        client_socket.async_connect(server_endpoint, 
            boost::bind(&Client::async_connect_handler, this, 
                boost::asio::placeholders::error));
    }

    void async_connect_handler(const boost::system::error_code &ec)
    {
        if (!ec)
        {
            std::cout << "Connected to chat server...\n";

            //wait for user input
            std::cin >> msg;
            std::cout << "\rC : " << msg << std::endl;

            client_socket.async_write_some(boost::asio::buffer(msg),
                boost::bind(&Client::async_write_some_handler, this, 
                    boost::asio::placeholders::error));
        }
        else
        {
            std::cout << "async_connect failed with error code : " << ec.value() << std::endl;
            std::cout << "Error description : " << ec.message() << std::endl;
        }
    }

    void async_write_some_handler(const boost::system::error_code &ec)
    {
        //wait for user input
        std::cin >> msg;
        std::cout << "\rC : " << msg << std::endl;

        client_socket.async_write_some(boost::asio::buffer(msg),
            boost::bind(&Client::async_write_some_handler, this, 
                boost::asio::placeholders::error));
    }
};

int main()
{
    boost::asio::io_context io;
    Client c(io);

    io.run();
    return 0;
}

Теперь проблема :

Работает нормально и тоже подключается к серверу,Я получаю правильное «Подключено к серверу чата ...» в клиенте и «Один клиент подключен ...» в сервере.После этого возникает проблема:

  1. В консоли сервера после сообщения «Один клиент» он просто ничего не печатает и продолжает и продолжает.
  2. Сообщения, отправленныеклиент никогда не отображается в консоли сервера.

Проблема 1 может быть проблемой с моей стороны, так как мне еще предстоит проверить функции ожидания и другие вызовы, которые заставляют сервер ждать.Если вы можете направить меня в этом, это будет более чем удивительно.Но главная проблема - это часть 2 проблемы , так как я понятия не имею, почему сервер всегда ничего не получает от клиента.

PS: Этонеполный код, и я планирую немного поиграть с ним, поэтому, если есть какие-то серьезные недостатки, пожалуйста, сообщите мне об этом ...Я прошел через все подобные вопросы.Например: это и это , но это не имеет значения.

1 Ответ

1 голос
/ 14 марта 2019

Каков размер string msg на стороне сервера? Это 0 . Таким образом, сервер всегда читает 0 байтов. Когда вы хотите прочитать строку и вызвать buffer::asio::buffer строка должна иметь некоторый размер, например 10. Это означает, что вы хотите прочитать 10 байтов в msg. Вы можете вызвать msg.resize(10) (до начала операции чтения), затем некоторые данные будут считаны в msg на async_read_some (это может быть 1,2 байта, что угодно - это как async_read_some работает, но максимум читать символы 10). Но это плохое решение.

Вы отправляете текст, поэтому вы можете рассмотреть возможность использования считанных данных в streambuf вместо string, когда вы не знаете, сколько байтов может поступить со стороны клиента. Затем вы можете вызвать async_read_until с разделителем - это может быть, например, символ новой строки.

Другим решением является использование динамического буфера . Где данные добавляются в строку, и вас не волнует начальный размер буфера строки. Но динамический буфер не работает с функциями-членами сокета, такими как async_read_some, его можно использовать с async_read как свободную функцию.

...