持久 Qt 本地套接字 IPC

发布于 2024-08-14 07:16:07 字数 2282 浏览 11 评论 0原文

我正在开发一个在本地服务器和客户端应用程序之间使用 IPC 的应用程序。它没有什么特别的,因为它的结构类似于 Qt 文档和示例。

问题在于客户端频繁发送数据包,并且与服务器本地套接字(NT 上的命名管道)的连接/断开速度非常慢。所以我想要实现的是两个应用程序之间的“持久”连接。

客户端应用程序连接到本地服务器(QLocalServer)没有任何问题:

void IRtsClientImpl::ConnectToServer(const QString& name)
{   
    connect(_socket, SIGNAL(connected()), this,  SIGNAL(connected()));
    _blockSize = 0;
    _socket->abort();
    _socket->connectToServer(name, QIODevice::ReadWrite);
}

并且也以传统的 Qt 方式发送请求:

void IRtsClientImpl::SendRequest( quint8 cmd, const QVariant* const param_array, 
                                 unsigned int cParams )
{
    // Send data through socket

    QByteArray hdr(PROTO_BLK_HEADER_PROJ);
    QByteArray dataBlock;
    QDataStream out(&dataBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_5);

    quint8 command = cmd;

    out << blocksize_t(0)   // block size
        << hdr      // header
        << quint32(PROTO_VERSION_PROJ) // protocol version
        << command            // command
        << cParams;           // number of valid parameters

    for (unsigned int i = 0; i < cParams; ++i)
        out << param_array[i];

    // Write the current block size
    out.device()->seek(0);
    out << dataBlock.size() - sizeof(blocksize_t);
    _socket->write(dataBlock);
}

没有问题。但诀窍在于服务器端的readyRead() 信号。这是readyRead()处理槽的当前实现:

void IRtsServerImpl::onReadyRead()
{
    QDataStream in(_lsock);
    in.setVersion(QDataStream::Qt_4_5);

    if (_blocksize == 0)
    {
        qDebug("Bytes Available on socket: %d", _lsock->bytesAvailable());
        if (_lsock->bytesAvailable() < sizeof(blocksize_t))
            return;

        in >> _blocksize;
    }

    // We need more data?
    if (_lsock->bytesAvailable() < _blocksize)
        return;

    ReadRequest(in);

    // Reset
    _blocksize = 0; 

}

如果不将_blocksize设置为零,我无法接收更多数据,只能接收第一个块组(我希望整个块在没有分段的情况下到达,因为这是通过管道,但事实并非如此,想想吧)。当然,我期望这种行为,因为 _blocksize 不再代表当前的流。好吧,重置 _blocksize 可以解决问题,但是如果没有在套接字上获得越来越多的字节数组,我就无法从客户端重新发送另一个数据包。我想要的是处理 ReadRequest 中的请求并接收下一个数据块,而不需要连接/重新连接所涉及的应用程序。

也许我应该“调节”传入数据的速率?

非常感谢。

I'm developing an application that uses IPC between a local server and a client application. There is nothing particular to it, as it's structured like the Qt documentation and examples.

The problem is that the client sends packets frequently and connecting/disconnecting from the server local socket (named pipe on NT) is very slow. So what I'm trying to achieve is a "persistent" connection between the two applications.

The client application connects to the local server (QLocalServer) without any problem:

void IRtsClientImpl::ConnectToServer(const QString& name)
{   
    connect(_socket, SIGNAL(connected()), this,  SIGNAL(connected()));
    _blockSize = 0;
    _socket->abort();
    _socket->connectToServer(name, QIODevice::ReadWrite);
}

And sends requests also in the traditional Qt manner:

void IRtsClientImpl::SendRequest( quint8 cmd, const QVariant* const param_array, 
                                 unsigned int cParams )
{
    // Send data through socket

    QByteArray hdr(PROTO_BLK_HEADER_PROJ);
    QByteArray dataBlock;
    QDataStream out(&dataBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_5);

    quint8 command = cmd;

    out << blocksize_t(0)   // block size
        << hdr      // header
        << quint32(PROTO_VERSION_PROJ) // protocol version
        << command            // command
        << cParams;           // number of valid parameters

    for (unsigned int i = 0; i < cParams; ++i)
        out << param_array[i];

    // Write the current block size
    out.device()->seek(0);
    out << dataBlock.size() - sizeof(blocksize_t);
    _socket->write(dataBlock);
}

No problem. But the trick resides on the readyRead() signal in the server-side. Here's the current implementation of the readyRead() handling slot:

void IRtsServerImpl::onReadyRead()
{
    QDataStream in(_lsock);
    in.setVersion(QDataStream::Qt_4_5);

    if (_blocksize == 0)
    {
        qDebug("Bytes Available on socket: %d", _lsock->bytesAvailable());
        if (_lsock->bytesAvailable() < sizeof(blocksize_t))
            return;

        in >> _blocksize;
    }

    // We need more data?
    if (_lsock->bytesAvailable() < _blocksize)
        return;

    ReadRequest(in);

    // Reset
    _blocksize = 0; 

}

Without setting _blocksize to zero I could not receive more data, only the first block group (I would expect an entire block to arrive without segmentation since this is through a pipe, but it does not, go figure). I expect that behavior, sure, since the _blocksize does not represent the current stream flow anymore. All right, resetting _blocksize does the trick, but I can't resend another packet from the client without getting an increasing array of bytes on the socket. What I want is to process the request in ReadRequest and receive the next data blocks without resorting to connecting/reconnecting the applications involved.

Maybe I should 'regulate' the rate of the incoming data?

Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文