I try to create a simple ssl connection between a client and a server in QtNetwork.
But I have a problem. First I run the server. Then I run the client. When I first run the client nothing happens, but when I run it second time I get QSslSocket::startServerEncryption: cannot start handshake on non-plain connection. I don't know how to fix it.
Here is the server:
//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 Source File :
//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 File :
//server main
#include "server.h"
#include <QCoreApplication>
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
Server server;
return app.exec();
}
Here is the Client :
//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 Source File :
// 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 File :
//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();
}
Anyone can tell me what's missing?
The problem here is that QSslSocket can't be reused (I opened a bug about this QTBUG-59348), so once you call setSocketDescriptor for the second time (once a new connection arives) the internal mode is in Encrypted state.
Your code also has the issue that even if QSslSocket could be reused, you create a single socket at the constructor, so you can only accept a single connection at time. You must instead create a new QSslSocket inside incommingConnection, and NO YOU DON'T NEED to call nextPendingConnection() if you have an implementation of QTcpServer, if you do you will get two objects pointing to the same FD, one QTcpSocket and one QSsqSocket created by you.
You should try to get the socket descriptor from the nextPendingConnection and set the socket descriptor of the QSslsocket
First: You have to connect the signal of the QTcpServer::newConnection with a self made slot (for example newConnectionRecognized)
Second: Set the socketDescriptor of the QSslSocket with the socket descriptor of the 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;
}
...
}
I hope it helped...
Related
I tried to run simple client-server app in QT. Problem is with "connect" on server side - newConnection slot isn't executed and exception appears (like in title).
***************myserver.cpp***********
#include "myserver.h"
myserver::myserver(){}
myserver::~myserver(){}
void myserver::startServer()
{
qDebug()<<"Starting startServer()";
tcpServer = new QTcpServer(this);
if (this->listen(QHostAddress::Any,1000))
{
qDebug()<<"Listening";
}
else
{
qDebug()<<"Not listening";
}
}
void myserver::incomingConnection(int socketDescriptor)
{
qDebug()<<"incomingConnection() started";
socket=new QTcpSocket(this);
socket->setSocketDescriptor(socketDescriptor);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
qDebug()<<socketDescriptor<<"Client connected";
}
void myserver::onNewConnection()
{
qDebug()<<"onNewConnection() started";
}
**********myserver.h**************
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QTcpServer>
#include <QTcpSocket>
class myserver: public QTcpServer
{
Q_OBJECT
public:
myserver();
~myserver();
QTcpSocket* socket;
QTcpServer *tcpServer=nullptr;
public slots:
void startServer();
void incomingConnection(int socketDescriptor);
void onNewConnection();
};
#endif // MYSERVER_H
***********testClient.cpp**************
#include "myclient.h"
#include "ui_myclient.h"
myclient::myclient(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::myclient)
{
ui->setupUi(this);
socket=new QTcpSocket(this);
connect(socket,SIGNAL(connected()),this,SLOT(socketMap()));
}
myclient::~myclient()
{
delete ui;
}
void myclient::on_pushButton_clicked()
{
socket->connectToHost("127.0.0.1",1000);
if(socket->isOpen())
{
qDebug()<<"Connected!";
}
else {
qDebug()<<"Not connected";
}
}
void myclient::socketMap()
{
qDebug()<<"socketMap() started";
}
I expected onNewConnection() being called when client connects. Also I have checked client side and connection is confirmed.
This is console output on server:
Starting startServer()
Listening
incomingConnection() started
948 Client connected
i'm planning do a little app desktop with Qt Creator. I'm using QUdpSocket class to make a simple connection through UDP, in fact i used a test code i found on internet, but my problem is when i run the code and the console just show me the port and the message, not the ip address where come from the message. Could someone tell me what i'm doing bad?
The source reference is this
This is the header file:
#ifndef PRUEBAUDP_H
#define PRUEBAUDP_H
#include <QObject>
#include <QUdpSocket>
#include <QDebug>
/*#include <QNetworkDatagram>
#include <QHostAddress>*/
class pruebaUDP : public QObject
{
Q_OBJECT
public:
explicit pruebaUDP(QObject *parent = nullptr);
void mensajeSocket();
signals:
public slots:
void readyRead();
private:
QUdpSocket *udpSocket;
};
#endif // PRUEBAUDP_H
This is the source file:
#include "pruebaudp.h"
pruebaUDP::pruebaUDP(QObject *parent) : QObject(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, 1234);
connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(readyRead()));
}
void pruebaUDP::mensajeSocket()
{
QByteArray dato;
dato.append("hola");
udpSocket->writeDatagram(dato, QHostAddress::LocalHost, 1234);
}
void pruebaUDP::readyRead()
{
QByteArray buffer;
buffer.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(buffer.data(), buffer.size(), &sender, &senderPort);
qDebug() << "Desde: " << sender.toString();
qDebug() << "mensaje del puerto: " << senderPort;
qDebug() << "mensaje: " << buffer;
}
and this is the main file:
#include <QCoreApplication>
#include "pruebaudp.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
pruebaUDP prueba;
prueba.mensajeSocket();
return a.exec();
}
This is a input screenshot:
You use same socket for sending and receiving.
Try to send data via other socket, i.e.
void pruebaUDP::mensajeSocket()
{
QByteArray dato;
dato.append("hola");
static QUdpSocket * socket = new QUdpSocket(this);
socket->writeDatagram(dato, QHostAddress::LocalHost, 1234);
}
Necessary informations:
QList<QTcpSocket*> list;
QTcpServer* server;
QTcpSocket* socket;
In Qt I have built a TCP-Server(QTcpServer)! I have a QList with all my connected clients and I want to read the incomming data for each client personally. So if the QTcpServer gets a new connection, I handel it like this:
void Server::newConnection()
{
qDebug() << "New Connection";
list.append(server->nextPendingConnection());
connect(list.last(),SIGNAL(readyRead()),this,SLOT(readyRead()));
}
How can I get the correct client (out of my QList), which send the SIGNAL readyRead(), in my SLOT readyRead()?
void Server::readyRead(){
//??
}
Any help is welcomed!
Have you tried QObject::sender()? It should return the instance of the QObject which actually sent the signal. Hope that will help.
The solution:
void Server::readyRead(){
QByteArray buffer;
QTcpSocket* readSocket = qobject_cast<QTcpSocket*>(sender());
buffer = readSocket->readAll();
QString mytext = QString::fromStdString(buffer);
qDebug() << mytext;
}
This could be solved by the QSignalMapper. Here is the (not completelly tested) code:
---------------------- main.cpp ------------------
#include "rootwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
RootWindow w;
w.show();
return a.exec();
}
---------------------- rootwindow.h ------------------------
#ifndef ROOTWINDOW_H
#define ROOTWINDOW_H
#include <QMainWindow>
#include <QtDebug>
#include <QLocalServer>
#include <QLocalSocket>
#include <QSignalMapper>
#include <QList>
class RootWindow : public QMainWindow
{
Q_OBJECT
private:
QLocalServer *server;
QLocalSocket *socket;
QList<QLocalSocket*> *list;
QSignalMapper *mapper;
public:
RootWindow(QWidget *parent = 0);
~RootWindow();
private slots:
void slotNewConnection();
void slotReadyRead(int index);
};
#endif // ROOTWINDOW_H
------------------------ rootwindow.cpp -------------------------
#include "rootwindow.h"
RootWindow::RootWindow(QWidget *parent): QMainWindow(parent)
{
server = new QLocalServer;
list = new QList<QLocalSocket*>;
mapper = new QSignalMapper(this);
connect(server, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
connect(mapper, SIGNAL(mapped(int)), this, SLOT(slotReadyRead(int)));
server->listen("TestServer");
}
RootWindow::~RootWindow()
{
delete list;
}
void RootWindow::slotNewConnection()
{
qWarning() << "newConnection";
list->append(server->nextPendingConnection());
//here you map each client to its number in the list
mapper->setMapping(list->last(), list->length()-1);
//here we say, that when ever a client from the QList sends readyRead() the mapper should be used
//with the property (list->length()-1) defined in the line above
connect(list->last(), SIGNAL(readyRead()), mapper, SLOT(map()));
}
void RootWindow::slotReadyRead(int index)
{
qWarning() << "Client " << index << " has written: " << list->at(index)->readAll();
}
It's basically your code, I've only added the QSignalMapper and some comments at the relevant lines.
I wrote a program for client on Qt to receive data from server but it is not receiving data and showing received bytes as zero,following is my program:
//client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include <QString>
#include <QtNetwork/QTcpSocket>
class Client: public QObject
{
Q_OBJECT
public:
Client(QObject* parent = 0);
~Client();
void start(QString address, quint16 port);
void send(const char*);
void receive();
public slots:
void startTransfer();
private:
QTcpSocket client;
};
#endif // CLIENT_H
//client.cpp
#include "client.h"
#include <QtNetwork/QHostAddress>
#include<QIODevice>
Client::Client(QObject* parent): QObject(parent)
{
connect(&client, SIGNAL(connected()),
this, SLOT(startTransfer()));
//connect(&client, SIGNAL(waitForBytesWritten()),
// this, SLOT(receive()));
}
Client::~Client()
{
client.close();
}
void Client::start(QString address, quint16 port)
{
QHostAddress addr(address);
client.connectToHost(addr, port);
}
void Client::startTransfer()
{
client.write("Connection Established", 22);
}
void Client::send(const char *buffer)
{
client.write(buffer,sizeof(buffer));
}
void Client::receive()
{
char temp[1024] = {0};
int len = client.read(temp,client.bytesAvailable());
printf("\tData recieved from server :: %s\n",temp);
printf("\tSize of data received is :: %d\n",client.bytesAvailable());
printf("\tBytes read is :: %d\n",len);
}
//main.cpp
#include <QCoreApplication>
#include "client.h"
//#include <QApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Client client;
client.start("192.168.1.2", 9602);
char buff[] = "Send operation performed from main";
client.send(buff);
// while(1)
client.receive();
return a.exec();
}
Here my program function executes and then stops receiving(may be),when I send any thing from server it doesn't take anything.Any suggestions?
Plz don't be rude if I have done any silly programming mistake because I'm newbie.
You are not getting #Merlin069's answer....you should use readyRead in signal's place and your receieve function as slot...it will work.I hope this much easy language is understandable to you.
You can try using while(1) and inside it write your receive function
I want to write a console chat program in qt framework.I have a problem with sending messages.
Client sends messages to server but server doesn't take the messages until client program is closed.When client is closed, server displays all messages.I don't want that.I want server to get my messages when i send to it.
I wrote the codes below.You will see what i want to do if you look at main function of client.
/*
Created BY :
Creation DATE : 26/10/2012
Client interface
*/
#ifndef CLIENT_H
#define CLIENT_H
#include <QtNetwork>
#include <QObject>
#include <QtNetwork/QTcpSocket>
namespace NetworkArdic
{
class Client : public QObject
{
Q_OBJECT
public:
Client(QObject * obj = 0,QString add="localhost", quint16 port = 4000);
void SendData(QString data);
virtual ~Client();
private slots:
void ReadData();
void connected();
private:
QTcpSocket *socket;
};
}
#endif
/*
Created BY :
Creation DATE : 26/10/2012
Client source file
*/
#include "Client.h"
#include <QHostAddress>
#include <iostream>
using namespace std;
namespace NetworkArdic{
Client::Client(QObject * obj, QString add, quint16 port) : QObject(obj)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(ReadData()));
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
socket->connectToHost(QHostAddress(add), port);
}
Client::~Client(){
socket->close();
delete socket;
}
void Client::SendData(QString data)
{
if(!data.isEmpty())
{
socket->write(QString(data + "\n").toUtf8());
}
}
void Client::ReadData()
{
while(socket->canReadLine())
{
QString line = QString::fromUtf8(socket->readLine()).trimmed();
qDebug() << line;
}
}
void Client::connected()
{
socket->write(QString("Client : Server connection has been made (: \n").toUtf8());
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Client cli(0,"127.0.0.1",4000);
string line;
while(line!="exit"){
cout << "Message : ";
cin >> line;
cli.SendData(QString(line.c_str()));
}
return a.exec();
}
/*
Created BY :
Creation DATE : 26/10/2012
Server interface
*/
#ifndef SERVER_H
#define SERVER_H
#include <QtNetwork>
#include <QObject>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
namespace NetworkArdic
{
class Server: public QTcpServer
{
Q_OBJECT
public:
Server(QObject * parent = 0 , quint16 port = 4000);
virtual ~Server();
private slots:
void acceptConnection();
void startRead();
void disconnected();
private:
QTcpSocket * client;
};
}
#endif // SERVER_H
/*
Created BY :
Creation DATE : 26/10/2012
Server source file
*/
#include "Server.h"
#include <iostream>
using namespace std;
namespace NetworkArdic{
Server::Server(QObject* parent , quint16 port): QTcpServer(parent)
{
connect(this, SIGNAL(newConnection()),this, SLOT(acceptConnection()));
listen(QHostAddress::Any, port );
}
Server::~Server()
{
delete client;
close();
}
void Server::acceptConnection()
{
client = nextPendingConnection();
connect(client, SIGNAL(readyRead()), this, SLOT(startRead()));
connect(client, SIGNAL(disconnected()), this, SLOT(disconnected()));
qDebug() << "New client from:" << client->peerAddress().toString();
}
void Server::startRead()
{
while(client->canReadLine())
{
QString line = QString::fromUtf8(client->readLine()).trimmed();
qDebug() << "Client :" << line;
client->write(QString("Server : I've taken your message (:\n").toUtf8());
}
}
void Server::disconnected()
{
qDebug() << "Client disconnected:" << client->peerAddress().toString();
client->write(QString("Server : I wish you didn't leave ):\n").toUtf8());
}
}
Try using socket->flush() after you write the data.
http://doc.qt.digia.com/qt/qabstractsocket.html#flush
You used the code below to read socket data.
void Server::startRead()
{
while(client->canReadLine())
{
QString line = QString::fromUtf8(client->readLine()).trimmed();
qDebug() << "Client :" << line;
client->write(QString("Server : I've taken your message (:\n").toUtf8());
}
}
I suggest to adopt from the following code which I have tested works
while (tcp_server->hasPendingConnections()) {
client = tcp_server->nextPendingConnection();
client->waitForReadyRead(100);
QByteArray byteArray = client->readAll();
QString s_data = byteArray.data();
// Process s_data
client->close();
client->abort();
}