0

QtNetworkでクライアントとサーバーの間に単純なSSL接続を作成しようとしています。

しかし、私には問題があります。まず、サーバーを実行します。次に、クライアントを実行します。クライアントを最初に実行したときは何も起こりませんが、2回目に実行したときに取得しQSslSocket::startServerEncryption: cannot start handshake on non-plain connectionます。修正方法がわかりません。

サーバーは次のとおりです。

//server.h

#ifndef SERVER_H
#define SERVER_H

#include <QtNetwork>
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QSslSocket>

class Server: public QTcpServer
{
    Q_OBJECT

public:
    Server(QObject * parent = 0);
    void incomingConnection(int handle);
    ~Server();

public slots:
    void startRead();

private:
    QSslSocket* socket;
};

#endif // SERVER_H

サーバーソースファイル:

//server.cpp

#include "server.h"
#include <iostream>
#include <QByteArray>
#include <QSslCertificate>
#include <QSslKey>
using namespace std;

Server::Server(QObject* parent) :
    QTcpServer(parent)
{
    socket = new QSslSocket;

    connect(socket, SIGNAL(encrypted()),
            this, SLOT(startRead()));

    listen(QHostAddress::Any, 8889);
}

void Server::startRead()
{
    char buffer[1024] = { 0 };
    socket->read(buffer, socket->bytesAvailable());
    cout << buffer << endl;
    socket->close();
}

void Server::incomingConnection(int socketDescriptor)
{
    if (socket->setSocketDescriptor(socketDescriptor))
    {
        connect(socket, SIGNAL(encrypted()),
                this, SLOT(startRead()));

        QByteArray key;
        QByteArray cert;

        QFile file_key("/path_to_key/rsakey");

        if(file_key.open(QIODevice::ReadOnly))
        {
            key = file_key.readAll();
            file_key.close();
        }
        else
        {
            qDebug() << file_key.errorString();
        }

        QFile file_cert("/path_to_certificate/mycert.pem");
        if(file_cert.open(QIODevice::ReadOnly))
        {
            cert = file_cert.readAll();
            file_cert.close();
        }
        else
        {
            qDebug() << file_cert.errorString();
        }

        QSslKey ssl_key(key, QSsl::Rsa);
        QSslCertificate ssl_cert(cert);

        socket->setPrivateKey(ssl_key);
        socket->setLocalCertificate(ssl_cert);

        QSslConfiguration cfg = socket->sslConfiguration();
        cfg.caCertificates();

        socket->startServerEncryption();
    }
}

Server::~Server()
{
    delete socket;
}

サーバーメインファイル:

//server main

#include "server.h"
#include <QCoreApplication>

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    Server server;

    return app.exec();
}

これがクライアントです:

//client.h
#ifndef CLIENT_H
#define CLIENT_H

#include <QtNetwork>
#include <QObject>
#include <QString>
#include <QSslSocket>

class Client: public QObject
{
    Q_OBJECT

public:
    Client(QObject* parent = 0);
    ~Client();
    void start(QString address, quint16 port);

public slots:
    void startTransfer();

private:
    QSslSocket client;
};


#endif // CLIENT_H

クライアントソースファイル:

// client.cpp

#include "client.h"
#include <QDebug>

Client::Client(QObject* parent) :
    QObject(parent)
{
    connect(&client, SIGNAL(encrypted()),
            this, SLOT(startTransfer()));
}

Client::~Client()
{
    client.close();
}

void Client::start(QString address, quint16 port)
{
    client.connectToHostEncrypted(address, port);
}

void Client::startTransfer()
{
    qDebug() << "startTransfer()";
    client.write("Hello, world", 13);
}

クライアントメインファイル:

//client main

#include "client.h"
#include <QCoreApplication>

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    Client client;
    client.start("127.0.0.1", 8889);

    return app.exec();
}

誰が私に何が欠けているのか教えてもらえますか?

4

2 に答える 2

3

ここでの問題は、QSslSocketを再利用できないことです(このQTBUG-59348に関するバグを開きました)。そのため、setSocketDescriptorを2回呼び出すと(新しい接続が確立されると)、内部モードは暗号化された状態になります。

コードには、QSslSocketを再利用できたとしても、コンストラクターで単一のソケットを作成するため、一度に1つの接続しか受け入れられないという問題もあります。代わりに、incommingConnection内に新しいQSslSocketを作成する必要があります。QTcpServerの実装がある場合は、nextPendingConnection()を呼び出す必要はありません。そうすると、同じFDを指す2つのオブジェクト、1つのQTcpSocketと1つのQSsqSocketが作成されます。あなたによって。

于 2017-03-07T18:19:35.273 に答える
0

nextPendingConnectionからソケット記述子を取得し、QSslsocketのソケット記述子を設定する必要があります

最初に:QTcpServer :: newConnectionのシグナルを自作のスロットに接続する必要があります(たとえば、newConnectionRecognized)

2番目:QSslSocketのsocketDescriptorをQTcpServer :: nextPendingConnection()->socketDescriptorのソケット記述子で設定します

constructor:
{
server = new QTcpServer;
...
server->listen(QHostAddress::Any,1234)
...
connect(server,SIGNAL(newConnection()),this,SLOT(newConnectionRecognized()));
...
}

void SslServer::newConnectionRecognized()
{
incomingConnection(server->nextPendingConnection()->socketDescriptor());
...
}

void SslServer::incomingConnection(int socket_descriptor)
{

   socket = new QSslSocket(this);

   ...

   if (!socket->setSocketDescriptor(socket_descriptor))
   {
      qWarning("! Couldn't set socket descriptor");
      delete socket;
      return;
   }

  ...
}

お役に立てば幸いです...

于 2013-08-13T16:04:34.027 に答える