Я пытаюсь создать простое соединение 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();
}
Кто-нибудь может сказать мне, чего не хватает?
Проблема в том, что QSslSocket не может быть повторно использован (я открыл ошибку по этому поводу QTBUG-59348), поэтому, когда вы вызываете setSocketDescriptor во второй раз (после установления нового соединения), внутренний режим находится в зашифрованном состоянии.
В вашем коде также есть проблема, заключающаяся в том, что даже если QSslSocket можно использовать повторно, вы создаете один сокет в конструкторе, поэтому вы можете принять только одно соединение за раз. Вместо этого вы должны создать новый QSslSocket внутри commingConnection, и НЕТ ВАМ НЕ НУЖНО вызывать nextPendingConnection (), если у вас есть реализация QTcpServer, если вы это сделаете, вы получите два объекта, указывающих на один и тот же FD, один QTcpSocket и один QSsqSocket. тобой.
Вы должны попытаться получить дескриптор сокета из 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;
}
...
}
Я надеюсь, что это помогло …