Как вы отправляете данные websocket подключенным клиентам с помощью C ++ Seasocks? - PullRequest
0 голосов
/ 28 апреля 2020

Я использую библиотеку Seasocks C ++ для добавления функциональности websocket в существующий проект. Как я могу инициировать отправку данных подключенным клиентам из кода C ++?

Пока мой код выглядит следующим образом:

// .....
#include "seasocks/PrintfLogger.h"
#include "seasocks/Server.h"
#include "seasocks/WebSocket.h"
#include <thread>

using namespace seasocks;

namespace {
    struct Handler : WebSocket::Handler {
        std::set<WebSocket*> _cons;
        void onConnect(WebSocket* con) override {
            _cons.insert(con);
            send("Connected");
        }
        void onDisconnect(WebSocket* con) override {
            _cons.erase(con);
            send("Disconnected");
        }
        void onData(WebSocket* con, const char* data) override {
            send(data);
        }
        void send(const std::string& msg) {
            for (auto* con : _cons) {
                con->send(msg);
            }
        }
    };
}
SmartConfig::SmartConfig(StorageContainer container, QObject *parent) : 
        QObject(parent),
        _storage(container),
        _webserver(NULL),
        _server(std::make_shared<PrintfLogger>())
{

    std::thread seasocksThread([&] {
        _server.addWebSocketHandler("/Socket", std::make_shared<Handler>(), true);
        _server.startListening(9090);
        _server.loop();
    });
    seasocksThread.detach();

    // .....
}

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

seasocks::Server().execute({
    send("Some data to send.");
});

Это не работает, однако. Я получаю следующую ошибку:

no instance of constructor "seasocks::Server::Server" matches the argument list

1 Ответ

1 голос
/ 28 апреля 2020

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

Функция execute() является методом объекта server, и она принимает «функция для вызова» в правильном потоке. Ваш пример пытается создать новый Server, а затем вызвать его метод execute со списком инициализаторов (я думаю!).

Для выполнения полезной работы вам необходимо знать, каких клиентов отправлять сообщения для. Сервер не отслеживает это: он делегирует эту ответственность отдельным Handler s. Думайте о Handler как об одном обработчике веб-страницы: на веб-сайте нет «клиентов», но на каждой странице есть (клиенты, которые ее просматривают)

Вам потребуется создать обработчик для страница, которую вы хотите (например, ChatHandler в руководстве). Этот обработчик запомнит список клиентов, прикрепленных к нему:

struct ChatHandler : WebSocket::Handler {
  set<WebSocket *> connections;
  void onConnect(WebSocket *socket) override 
    { connections.insert(socket); }
  void onData(WebSocket *, const char *data) override 
    { for (auto c : connections) c->send(data); }
  void onDisconnect(WebSocket *socket) override 
    { connections.erase(socket); }
};

// I'd never use globals normally but for simplicity:
std::shared_ptr<ChatHandler> chatHandler;
Server server(make_shared<PrintfLogger>());

void chat() {
  chatHandler = make_shared<ChatHandler>();
  server.addWebSocketHandler("/chat", chatHandler);
  server.serve("web", 9090);
}

В этом примере клиент чата просто отображает данные, которые он получает, всем подключенным клиентам. Поскольку метод onData вызывается из потока Seasocks, shenanigans execute() не требуется.

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

void sendToAll(const char *data) {
  server.execute([] {
    for (auto c : chatHandler->connections) c->send(data);
  });
}

При этом создается анонимная функция (лямбда), которая входит в обработчик чата и вызывает "send" на каждом из своих клиентов. Затем он передает эту лямбду в server.execute() - это гарантирует, что лямбда будет выполнена в правильном потоке.

Специально для вашего случая я бы предложил:

  • Сохранение Handler shared_ptr, который вы создаете в структуре SmartConfig. Сделайте shared_ptr<Handler> переменную-член (_handler), создайте ее и затем также передайте в addWebSocketHandler.
  • Если вы хотите отправить на все соединения, позвоните _server.execute([this, msg]{ _handler.send(msg);});

Надеюсь, это немного поможет: это не так ясно, и синтаксис C ++ не самый простой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...