Обмен сообщениями Boost Sockets С++

В настоящее время я пытаюсь создать соединение между сервером и клиентом для отправки XML-документов. Представляется, что эти документы можно отправить после их сериализации. Мой план состоит в том, чтобы установить соединение, отправить одно сообщение от клиента на сервер (список фильтров), а затем отправить N сообщений со стороны сервера, когда сообщение соответствует критериям фильтров.

Однако, прежде чем перейти к этому, я хотел попробовать простую реализацию этого, используя только строки, чтобы увидеть, как это работает, и лучше понять библиотеку boost asio.

Затем я реализовал свою серверную часть:

#include <iostream>
#include <thread>
#include <queue>
#include <chrono>
#include <array>
#include <boost/asio.hpp>

int main()
{
    const int BACKLOG_SIZE = 30;
    unsigned short PORT = 3333;

    // Endpoint and io_service creation
    boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address_v4::any(),PORT);
    boost::asio::io_service ios;

    boost::asio::ip::tcp::acceptor acceptor(ios, ep.protocol());

    // Binding to client
    acceptor.bind(ep);

    acceptor.listen(BACKLOG_SIZE);

    boost::asio::ip::tcp::socket socket(ios);
    // accepting connection (blocking process) 
    acceptor.accept(socket);

    std::cout << "Binded" << std::endl;

    // Receiving data from client

    boost::asio::streambuf sb;
    boost::system::error_code ec;
    
    while (boost::asio::read(socket, sb, ec))
    {
        std::cout << "received: " << &sb << "\n";
        if (ec)
        {
            std::cout << "status: " << ec.message() << "\n";
            break;
        }
    }

    // Sending data to client

    socket.send("Filters received!");

}

и моя клиентская часть:

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

int main()
{
    std::string raw_ip_address = "127.0.0.1";
    unsigned short port_num = 3333;
    std::string FILTER = "ATL";

    try {
        // Endpoint creation
        boost::asio::ip::tcp::endpoint
            ep(boost::asio::ip::address::from_string(raw_ip_address),
                port_num);

        boost::asio::io_service ios;

        // Creating and opening a socket.
        boost::asio::ip::tcp::socket sock(ios, ep.protocol());

        // Connecting a socket.
        sock.connect(ep);

        // Sending data to server

        std::cout << "Connected to " << raw_ip_address << " Port: " << port_num << std::endl;

        sock.send(boost::asio::buffer(FILTER));

        boost::asio::streambuf sb;
        boost::system::error_code ec;

        // Receiving data from server

        while (boost::asio::read(socket, sb, ec))
        {
            std::cout << "received: " << &sb << "\n";
            if (ec)
            {
                std::cout << "status: " << ec.message() << "\n";
                break;
            }
        }
    }
    // Overloads of asio::ip::address::from_string() and 
    // asio::ip::tcp::socket::connect() used here throw
    // exceptions in case of error condition.
    catch (boost::system::system_error& e) {
        std::cout << "Error occured! Error code = " << e.code()
            << ". Message: " << e.what();

        return e.code().value();
    }

    return 0;
}

Сначала я начал только с отправки фильтров с клиента на сервер, и все это работало хорошо. Однако, когда я попытался добавить ответ от сервера к клиенту, это вызвало ошибку, которую я действительно не понимаю: ошибка

Кто сталкивался с этой проблемой и знает как ее решить? Возможно ли вообще установить такое соединение, при котором обе стороны сокета могут отправлять сообщения по своему усмотрению (как я уже сказал, идея будет заключаться в том, чтобы сервер отправлял N сообщений из другого приложения после получения списка фильтров).

Спасибо за вашу помощь.

Вы всегда должны публиковать ошибку в виде текста, а не изображения в stackoverflow.

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

Ответы 1

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

Первая проблема: строковые литералы не являются буфером (или буферной последовательностью).

Вам нужно описать буфер, например. вот так:

std::string response("Filters received!");
socket.send(boost::asio::buffer(response));

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

socket.send(boost::asio::buffer("Filters received!"sv));

Вторая проблема:

    while (boost::asio::read(socket, sb, ec)) {

Это не может работать, потому что вы имели в виду sock, а не socket (который существует, но есть ::socket, введите int(&)(int,int,int).

Тем не менее, чтение в EOF в цикле while не очень полезно, так как цикл всегда прерывается из-за EOF (или другой ошибки).

Наконец, поскольку в настоящее время клиент никогда не закроет сокет, пока не будет получен ответ, будет неопределенное ожидание обеих программ. Рассмотрим частичное отключение:

    sock.send(asio::buffer(FILTER));
    sock.shutdown(tcp::socket::shutdown_send);

Вот клиент и сервер вместе

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

#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
using boost::system::error_code;
using namespace std::string_view_literals;

static const std::string raw_ip_address = "127.0.0.1";
static const std::string FILTER         = "ATL";
static const int         BACKLOG_SIZE   = 30;
static const uint16_t    PORT           = 3333;

int main(int argc, char**) {
    asio::io_service ios;
    asio::streambuf  sb;
    error_code       ec;

    try {
        if (argc > 1) { // client
            tcp::endpoint ep({}, PORT);

            tcp::socket sock(ios, ep.protocol());
            sock.connect(ep);

            // Sending data to server
            std::cout << "Connected to " << sock.remote_endpoint() << std::endl;

            sock.send(asio::buffer(FILTER));
            sock.shutdown(tcp::socket::shutdown_send);

            read(sock, sb, ec);
            std::cout << "received: " << &sb << "\n"
                      << "status: " << ec.message() << "\n";
        } else // server
        {
            tcp::acceptor acceptor(ios, tcp::v4());
            acceptor.bind({{}, PORT});
            acceptor.listen(BACKLOG_SIZE);

            tcp::socket sock(ios);
            acceptor.accept(sock);

            std::cout << "Accepted " << sock.remote_endpoint() << std::endl;

            read(sock, sb, ec);
            std::cout << "received: " << &sb << "\n"
                      << "status: " << ec.message() << "\n";

            sock.send(asio::buffer("Filters received!"sv));
        }
    } catch (boost::system::system_error& e) {
        std::cout << "Error occured! Error code = " << e.code()
                  << ". Message: " << e.what() << "\n";

        return 1; // e.code().value() not very useful, as the category is lost
    }
}

Запуск и сборка, например.

g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -isystem /usr/local/include/ 
./a.out&
sleep 1; ./a.out client

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

Connected to 127.0.0.1:3333
Accepted 127.0.0.1:50816
received: ATL
status: End of file
received: Filters received!
status: End of file

Спасибо, это решило мою проблему с отправкой обратных сообщений. Я разделил код, чтобы можно было запускать и сервер, и клиент на разных кодах. Однако без цикла while в функции чтения я не могу попросить клиентскую сторону ждать дополнительных сообщений от сервера. Идея этого асинхронного обмена сообщениями заключается в том, что клиент ожидает возможного сообщения от сервера и обрабатывает каждое из них индивидуально, когда оно доступно. Насколько я понимаю, даже если я отправлю 3 сообщения, все 3 будут получены клиентом в один и тот же момент. (Я исправил свой комментарий, чтобы быть более точным)

AirTrav 20.10.2022 21:54

В любом случае вы не можете, потому что вы не определили «сообщение» - и ваше чтение никогда не завершается, пока отправляющая сторона не отключит соединение. Кроме того, ваш обмен сообщениями является синхронным.

sehe 20.10.2022 23:02

Если вы хотите кадрирование, определите кадрирование. Например: coliru.stacked-crooked.com/a/95a8a52573f29dba

sehe 20.10.2022 23:24

А вот и все асинхронно, с несколькими параллельными клиентами в одной программе: coliru.stacked-crooked.com/a/0cdb0ef5c6e0c542

sehe 21.10.2022 00:13

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