Qt 5.6使用QLocalServer和QLocalSocket传递文件描述符

时间:2016-06-06 01:34:17

标签: linux qt sockets qt5 file-descriptor

我正在学习如何在Ubuntu 14.04上使用带有Qt 5.6的Unix域套接字传递文件描述符。从文档中可以看出,执行此操作的方法是使用QLocalServer和QLocalSocket类。

我创建了2个简单的应用程序,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();

}

1 个答案:

答案 0 :(得分:1)

在Linux上使用Unix域套接字发送文件描述符是使用SCM_RIGHTS类型的辅助数据完成的。 Qt似乎不支持QLocalSocketQLocalServer这样的数据,有一个旧的QTBUG正在讨论这个问题。它似乎还没有解决。

您可以使用Qt D-Bus使用QDBusUnixFileDescriptor类发送文件描述符。或者我担心您可能必须使用Unix域套接字来自行实现,有一个很好的例子{ {3}}

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

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