0

我尝试在 QtNetwork 中的客户端和服务器之间创建一个简单的 ssl 连接。

但我有一个问题。首先我运行服务器。然后我运行客户端。当我第一次运行客户端时没有任何反应,但是当我第二次运行它时,我得到了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 (一旦一个新的连接出现),内部模式就处于加密状态。

您的代码还有一个问题,即即使可以重用 QSslSocket,您也会在构造函数中创建一个套接字,因此您一次只能接受一个连接。相反,您必须在 incommingConnection 中创建一个新的 QSslSocket,如果您有 QTcpServer 的实现,您不需要调用 nextPendingConnection(),如果您这样做,您将获得两个指向同一个 FD 的对象,一个 QTcpSocket 和一个 QSsqSocket 创建由你。

于 2017-03-07T18:19:35.273 回答
0

您应该尝试从 nextPendingConnection 获取套接字描述符并设置 QSslsocket 的套接字描述符

首先:您必须将 QTcpServer::newConnection 的信号与自制插槽连接(例如 newConnectionRecognized)

二:用QTcpServer::nextPendingConnection()->socketDescriptor的socket描述符设置QSslSocket的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 回答