Простой клиент / сервер QSsl: не может запустить рукопожатие при непрозрачном соединении

Я пытаюсь создать простое соединение ssl между клиентом и сервером в QtNetwork.

Но у меня есть проблема. Сначала я запускаю сервер. Затем я запускаю клиент. При первом запуске клиента ничего не происходит, но когда я запускаю его во второй раз, я получаю 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();
}

Кто-нибудь может сказать мне, чего не хватает?

0

Решение

Проблема в том, что QSslSocket не может быть повторно использован (я открыл ошибку по этому поводу QTBUG-59348), поэтому, когда вы вызываете setSocketDescriptor во второй раз (после установления нового соединения), внутренний режим находится в зашифрованном состоянии.

В вашем коде также есть проблема, заключающаяся в том, что даже если QSslSocket можно использовать повторно, вы создаете один сокет в конструкторе, поэтому вы можете принять только одно соединение за раз. Вместо этого вы должны создать новый QSslSocket внутри commingConnection, и НЕТ ВАМ НЕ НУЖНО вызывать nextPendingConnection (), если у вас есть реализация QTcpServer, если вы это сделаете, вы получите два объекта, указывающих на один и тот же FD, один QTcpSocket и один QSsqSocket. тобой.

1

Другие решения

Вы должны попытаться получить дескриптор сокета из nextPendingConnection и установить дескриптор сокета QSslsocket

Во-первых: вы должны соединить сигнал QTcpServer :: newConnection с самостоятельно созданным слотом (например, newConnectionRecognized)

Второе: установить socketDescriptor QSslSocket с помощью дескриптора сокета 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;
}

...
}

Я надеюсь, что это помогло …

0

По вопросам рекламы [email protected]