0

我已经在 QCoreApplication 中实现了一个 websocket 服务器。一旦与客户端建立连接,我希望立即实时向它发送一系列消息,消息0.5之间有几秒钟的延迟。但是,只有在所有消息都已发送后或sendMyMessages()在我的 websocket 服务器的以下实现中方法返回后,单独的消息才会到达客户端。如果我要发送大量消息,客户端必须等待很长时间才能一次性收到所有消息。

MyWebSocketServer.h

#ifndef MYWEBSOCKETSERVER_H
#define MYWEBSOCKETSERVER_H

#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QByteArray>

QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)

class MyWebSocketServer : public QObject
{
    Q_OBJECT
public:
    explicit MyWebSocketServer(quint16 port,
                                        bool debug = false,
                                        QObject *parent = nullptr);
    ~MyWebSocketServer();

Q_SIGNALS:
    void closed();

private Q_SLOTS:
    void onNewConnection();
    void socketDisconnected();

private:
    void sendMyMessages(QWebSocket *client);

    QWebSocketServer *m_pWebSocketServer;
    QList<QWebSocket *> m_clients;
    bool m_debug;
};

#endif // MYWEBSOCKETSERVER_H

MyWebSocketServer.cpp

#include "MyWebSocketServer.h"

#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>

#include <QtWebSockets/qwebsocketserver.h>
#include <QtWebSockets/qwebsocket.h>
#include <QtCore/QDebug>

QT_USE_NAMESPACE


MyWebSocketServer::MyWebSocketServer(quint16 port,
                                     bool debug,
                                     QObject *parent)
    : QObject(parent)
    , m_pWebSocketServer(new QWebSocketServer(
                           QStringLiteral("My WebSocket Server"),
                           QWebSocketServer::NonSecureMode,
                           this))
    , m_debug(debug)
{
    connect(m_pWebSocketServer,
            &QWebSocketServer::newConnection,
            this,
            &MyWebSocketServer::onNewConnection);
    connect(m_pWebSocketServer,
            &QWebSocketServer::closed,
            this,
            &MyWebSocketServer::closed);

    m_pWebSocketServer->listen(QHostAddress::LocalHost, port);
}

MyWebSocketServer::~MyWebSocketServer()
{
    m_pWebSocketServer->close();
    qDeleteAll(m_clients.begin(), m_clients.end());
}

void MyWebSocketServer::onNewConnection()
{
    QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
    connect(pSocket,
            &QWebSocket::disconnected,
            this,
            &MyWebSocketServer::socketDisconnected);

    m_clients << pSocket;
    sendMyMessages(pSocket);
}

void MyWebSocketServer::sendMyMessages(QWebSocket *client)
{
    std::fstream jsonStringFileHandler;
    jsonStringFileHandler.open("my-messages.txt", std::ios::in);

    if (jsonStringFileHandler.is_open())
    {
        std::string message;
        while(getline(jsonStringFileHandler, message))
        {
            // Individual messages don't go through immediately
            // Only after this method returns, all the messages show up on the client's end
            // Is it possible to send the individual messages immediately? (probably with a 0.5 second delay)
            client->sendTextMessage(QString::fromUtf8(message.c_str()));
        }
        jsonStringFileHandler.close();
    }
}

void MyWebSocketServer::socketDisconnected()
{
    QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
    if (pClient)
    {
        m_clients.removeAll(pClient);
        pClient->deleteLater();
    }
}

只有在sendMyMessages()返回之后,客户端才能获得所有消息。它不是实时的。我知道在使用一些异步编程技术之后可以实现我的目标,但我无法找到一种方法来在我的 websocket 服务器实现中进行设置。

这是使用websocketsandasyncio模块在 Python 中为我工作的 websocket 服务器的实现。但是,我希望使用 Qt 在 C++ 中实现相同的逻辑。

import asyncio
import websockets

async def sendMyMessages(websocket, path):
    with open("my-messages.txt") as fp:
        lines = fp.readlines()
        for line in lines:
            await asyncio.sleep(0.5)
            await websocket.send(line.strip())

start_server = websockets.serve(sendMyMessages, "127.0.0.1", 3000)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
4

1 回答 1

0

我发现其中一种方法QWebSocket::flush()在调用QWebSocket::sendTextMessage().

从上的文档QWebSocket::flush()

该函数尽可能多地从内部写入缓冲区写入底层网络套接字,而不阻塞。如果写入了任何数据,则此函数返回 true;否则返回 false。如果您需要 QWebSocket 立即开始发送缓冲数据,请调用此函数。成功写入的字节数取决于操作系统。在大多数情况下,您不需要调用此函数,因为一旦控制返回事件循环,QWebSocket 就会自动开始发送数据。

但是,我不确定这是否是正确的方法,因为文档表明数据可能无法可靠地写入底层网络套接字。我很高兴知道是否有更好的技术!

client->sendTextMessage(QString::fromUtf8(message.c_str()));
client->flush();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
于 2021-03-28T22:31:52.123 回答