【问题标题】:Qt 5.6 Passing File Descriptors with QLocalServer and QLocalSocketQt 5.6 使用 QLocalServer 和 QLocalSocket 传递文件描述符
【发布时间】:2016-06-06 01:34:17
【问题描述】:

我正在学习如何在 Ubuntu 14.04 上使用带有 Qt 5.6 的 Unix 域套接字传递文件描述符。从文档中,听起来这样做的方法是使用 QLocalServer 和 QLocalSocket 类。

我创建了 2 个简单的应用程序,1 个服务器和 1 个客户端。他们每个人只有 1 个班级,我在下面粘贴了整个班级。

我可以将“文件描述符”作为整数接收,但是当我尝试以附加模式打开它以便在客户端进程中写入它时,我收到以下错误:

Cannot open existing file handle:  "Unknown error"
QIODevice::write: device not open
FD Received:  20

我做错了什么?

客户:

#include <QtWidgets>
#include <QtNetwork>

#include "localclient.h"

Client::Client(QObject *parent)
{

    socket = new QLocalSocket(this);
    connect(socket, SIGNAL(readyRead()), this, SLOT(readFd()));
    connect(socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(displayError(QLocalSocket::LocalSocketError)));

    requestFd();

}

void Client::requestFd()
{

    socket->abort();
    socket->connectToServer("mysocket");

}

void Client::readFd()
{

    QDataStream in(socket);
    in.setVersion(QDataStream::Qt_4_0);

    if (socket->bytesAvailable() < (int)sizeof(quint16))
        return;

    if (in.atEnd())
        return;

    int nextFd;
    in >> nextFd;

    QFile rxFile;
    if ( !rxFile.open(nextFd,QIODevice::Append) ) {
        qDebug() << "Cannot open existing file handle: " << rxFile.errorString();
    }
    rxFile.write("hello");

    qDebug() << "FD Received: " << nextFd;

}

void Client::displayError(QLocalSocket::LocalSocketError socketError)
{
    switch (socketError) {
    case QLocalSocket::ServerNotFoundError:
        tr("The host was not found. Please check the "
           "host name and port settings.");
        break;
    case QLocalSocket::ConnectionRefusedError:
        tr("The connection was refused by the peer. "
           "Make sure the fortune server is running, "
           "and check that the host name and port "
           "settings are correct.");
        break;
    case QLocalSocket::PeerClosedError:
        break;
    default:
        tr("The following error occurred: %1.").arg(socket->errorString());
    }

}

服务器:

#include <QtWidgets>
#include <QtNetwork>

#include <stdlib.h>

#include "localserver.h"
#include <qlocalserver.h>
#include <qlocalsocket.h>

Server::Server(QObject *parent)
{

    server = new QLocalServer(this);
    if (!server->listen("mysocket")) {
        qDebug() << QString("Unable to start the server: %1.").arg(server->errorString());
        return;
    }

    qDebug() << tr("The server is running");

    connect(server, SIGNAL(newConnection()), this, SLOT(sendFd()));

    fileToSend = new QFile("/home/me/Desktop/test.bin");
    if ( !fileToSend->open(QIODevice::WriteOnly) ) {
        qDebug() << "Unable to open file to send";
    }

}

void Server::sendFd()
{

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);
    out.device()->seek(0);
    qDebug() << "Sending this file handle: " << fileToSend->handle();
    out << fileToSend->handle();

    QLocalSocket *clientConnection = server->nextPendingConnection();
    connect(clientConnection, SIGNAL(disconnected()),
            clientConnection, SLOT(deleteLater()));

    clientConnection->write(block);
    clientConnection->flush();
    clientConnection->disconnectFromServer();

}

【问题讨论】:

    标签: linux qt sockets qt5 file-descriptor


    【解决方案1】:

    在 linux 上,使用 Unix 域套接字发送文件描述符是使用 SCM_RIGHTS 类型的辅助数据完成的。 Qt 似乎不支持使用QLocalSocketQLocalServer 的此类数据,有一个老的QTBUG 在谈论这个问题。而且好像还没有解决。

    你可以使用Qt D-Bus,在那里你可以使用QDBusUnixFileDescriptor类发送文件描述符。或者恐怕你可能不得不使用Unix域套接字来自己实现,有一个很好的例子here

    但是你确定你真的需要在你的应用程序之间传递文件描述符吗?出于学习目的以外的目的,我认为总有办法克服这个限制。

    附:您正在使用QDataStream 序列化套接字文件描述符(就好像它是一个普通的int),然后将序列化数据发送给另一个进程以将其作为普通的int 读取。这将允许您读取文件描述符的整数值,但您将不允许与它进行任何交互,因为文件描述符值在它们所属的进程之外没有意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多