c++ - 简单 QSsl 客户端/服务器 : cannot start handshake on non-plain connection

标签 c++ qt ssl client-server qsslsocket

我尝试在 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();
}

谁能告诉我缺少什么?

最佳答案

这里的问题是 QSslSocket 不能被重用(我打开了一个关于这个的错误 QTBUG-59348 ),所以一旦你第二次调用 setSocketDescriptor (一旦一个新的连接到达)内部模式就处于加密状态。

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

关于c++ - 简单 QSsl 客户端/服务器 : cannot start handshake on non-plain connection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15213139/

相关文章:

c++ - jsoncpp中区分int和uint类型

Qt/C++ 事件循环异常处理

c++ - C++中的线程问题

c++ - 用 define 替换两次函数调用

ssl - 多个 Internet 站点的 Lotus/IBM Domino 服务器 SSL 配置

ssl - 使用 SSL/TLS 的 RabbitMQ 普通身份验证

c++ - gcc 4.9.1 不符合标准? (std::runtime_error)

c++ - `typedef enum {} t` 是否允许 C++0x 中的作用域枚举元素标识符?

c++ - tbb::concurrent_hash_map - 如果键输入被其他线程阻塞,如何返回

Java NIO SSL - SSLEngine session 重用