В предыдущей части мы написали простейший обработчик подключений и класс, объекты которого будут обрабатывать эти подключения.
Для того что бы наш сервер, как то реагировал на другие события, кроме как обрабатывал одно подключения, его нужно вынести в отдельный поток. Но при таком подходе при большом количестве подключений будет создано много потоков и Ваша система просто рухнет. Что бы обезопасить себя необходимо использовать пул потоков, или просто ограничить количество подключаемых клиентов. Но это уже в следующий раз опишем, а сейчас напишем наш обработчик подключений, добавив при этом в перечисление enum class Error строчку, которая говорит о коде ошибку, если у нас что то пошло не так с сокетом.
SOCKET_SETUP_ERROR = 2
обработчик подключений:
void SslServer::incomingConnection(qintptr handle)
{
qDebug()<<"incomingConnection on socket:"<setSocket(handle)) {
//создаем новый поток и запускаем его
QThread* threadForClient = new QThread();
clientConnection->moveToThread(threadForClient);
threadForClient->start();
} else {
/*
* если нам не удалось по какойто причине установить сокет
* то освобождаем ресурсы и посылаем сигнал чо у нас ошибка на серве,
* с кодом Error::SOCKET_SETUP_ERROR
*
*/
qDebug()<<"socket setup error;";
delete clientConnection;
emit error(Error::SOCKET_SETUP_ERROR);
}
}
Теперь, если мы запустим наш сервер и попытаемся к нему подключится(через тот же телнет), то мы увидим информацию об ошибках и предупреждениях.
И это вполне нормально, ведь мы указали что для соединения мы используем ключи. Если открыть документацию по перечислению QAbstractSocket::SocketError, то мы увидим следующее:
13 The SSL/TLS handshake failed, so the connection was closed (only used in QsslSocket)
Что означает что при установки соединения возникла ошибка с так называемым ssl рукопожатием.
На этом пока реализации сервера отложим и напишем небольшой клиент, для того что мы спокойно могли продолжать разрабатывать сервер.
Создадим новый проект (консольное приложения). В файле проекта также допишем строчки
QT += network
CONFIG += c++11
Создаем новый класс Connection и наследуемся от Qobject. В данном классе мы реализуем логику подключения на сервер. В данном классе создади один публичный метод connectToServer который будет подключатся к нашему серверу.
Также необходимо создать поле, которое будет в себе хранить сокет, и соединить сигналами которые поступают от него со слотами, которые необходимо определить в данном классе.
Таким образом заголовок нашего класса выглядит следующим образом:
class Connection : public QObject
{
Q_OBJECT
public:
explicit Connection(QObject *parent = 0);
void connectToServer();
private:
QSslSocket *sslsocket;
signals:
public slots:
void readyRead();
void encrypted();
void connected();
void disconnected();
void socketError(QAbstractSocket::SocketError error);
void socketSslErrors(const QList &list);
};
Самым важным методом является connectToServer, в нем необходимо подключится к серверу, указав при этом сертификат, который сгенерировали при помощи openssl. Обратите внимание что, я подключаюсь к серверу, расположенному по адресу 127.0.0.1, соответственно в сертификате я должен указать в поле Common Name адрес 127.0.0.1.
void Connection::connectToServer()
{
this->sslsocket->connectToHostEncrypted("127.0.0.1",1234);
this->sslsocket->addCaCertificates("key.pem");
if (this->sslsocket->waitForEncrypted()) {
qDebug()<<"connected";
this->sslsocket->write("hello");
if(this->sslsocket->waitForBytesWritten()) {
qDebug()<<"send msg";
} else {
qDebug()<sslsocket->errorString();
}
} else {
qDebug()<<"error:"<sslsocket->errorString();
}
}
На сервере в слоте получения сигнала что есть данные для чтения пропишем вывод о том на какой сокет пришел сигнал и выводим сами данные.
Connection* connection = new Connection();
connection->connectToServer();
Что же пришло запустить на сервер и поробывать подключится к нему с нашего клиента. В клиенте в функции main укажем:
Запускаем сервер и запускаем клиент
Сервер:
Клиент:
Как видно из изображений,мы успешно установили соединения и послали нашему серверу «hello». Если мы запустим еще один клиент то увидим новое соединения и новое «hello», только уже на другом дескрипторе сокета.
Комментарий (0)