Reputation: 45
I'm making a server-client system for a client placed within a loop to continuously query a predetermined set of information from a server. I've cooked up a bit of code from what I could understand about how the TCP implementation of the Qt framework works but I'm not sure if what I have written is the right way to do it.
At first, I made an enum with a bunch of QByteArray
variables in the client QTcp class to pass as a query from the client side to the server as shown below
enum datamap
{
QByteArray data1 = 1;
QByteArray data2 = 2;
QByteArray data3 = 3;
// and so on...
};
Then I make the function that takes in an enum datamap
variable to pass to the server and a variable to hold the current request(to avoid mixup between data received for the wrong request) as shown below
datamap current_request = 0;
int client::setDataToGet(datamap& data)
{
if(socket->state() == QAbstractSocket::ConnectedState)
{
current_request = data;
socket->write(data);
return socket->waitForBytesWritten();
}
else
return -1;
}
After this, I create the readyRead()
slot that connects to the readyread
signal to handle responses from the server and send to functions that will display the received data in the respective text box based on the current_request
variable as shown below
void client::readyRead()
{
QTcpSocket *m_socket = static_cast<QTcpSocket*>(sender());
while(m_socket->bytesAvailable() > 0)
{
QByteArray buf = socket->readAll();
}
switch(current_request):
case 1:
dispToTextBox1(buf);
case 2:
dispToTextBox2(buf);
case 3:
dispToTextBox3(buf);
// and so on....
}
Now, for the server side, I make the readyRead()
slot that connects to the readyread()
signal from a socket listener called in the newConnection()
function.
This takes in the handle from the client and accordingly is supposed to return back data associated with the handle. The code for the slot is as follows
void server::readyRead()
{
QTcpSocket *m_socket = static_cast<QTcpSocket*>(sender());
while(m_socket->bytesAvailable() > 0)
{
QByteArray buf = m_socket->readAll();
}
switch(buf):
case 1:
data = collectDatafromStream1();
m_socket->write(data); m_socket->flush();
case 2:
data = collectDatafromStream2();
m_socket->write(data); m_socket->flush();
case 3:
data = collectDatafromStream3();
m_socket->write(data); m_socket->flush();
//and so on.....
}
Could someone please verify if this is the right way to do this or if there is a better alternative for handling the task.
Upvotes: 0
Views: 362
Reputation: 45
Got the concept model to work with a few changes. Used the response given by "sashoalm" in this question to pass the data using QdataStream and used signals & slots to cycle through the read-write sequence for each request type.
my server class is as follows
tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include<qt5/QtNetwork/QTcpServer>
#include<qt5/QtNetwork/QTcpSocket>
#include<qt5/QtCore/QObject>
class TCPServer : public QObject
{
Q_OBJECT
public:
explicit TCPServer(QObject *parent = nullptr);
signals:
void dataReceived(QByteArray);
private slots:
void newConnection();
void disconnected();
void readyRead();
private:
QTcpServer *server;
QTcpSocket *socket;
QHash<QString, int> reverse_hash;
};
#endif // TCPSERVER_H
tcpserver.cpp
#include <iostream>
#include "tcpserver.h"
#include <qt5/QtCore/QDataStream>
#include <qt5/QtCore/QBuffer>
#include <qt5/QtCore/QString>
class BlockWriter
{
public:
BlockWriter(QIODevice *io)
{
buffer.open(QIODevice::WriteOnly);
this->io = io;
_stream.setVersion(QDataStream::Qt_4_8);
_stream.setDevice(&buffer);
_stream << quint64(0);
}
~BlockWriter()
{
_stream.device()->seek(0);
_stream << static_cast<quint64>(buffer.size());
io->write(buffer.buffer());
}
QDataStream &stream()
{
return _stream;
}
private:
QBuffer buffer;
QDataStream _stream;
QIODevice *io;
};
class BlockReader
{
public:
BlockReader(QIODevice *io)
{
buffer.open(QIODevice::ReadWrite);
_stream.setVersion(QDataStream::Qt_4_8);
_stream.setDevice(&buffer);
qint64 blockSize;
readMax(io, sizeof(blockSize));
buffer.seek(0);
_stream >> blockSize;
readMax(io, blockSize);
buffer.seek(sizeof(blockSize));
}
QDataStream& stream()
{
return _stream;
}
private:
void readMax(QIODevice *io, qint64 n)
{
while (buffer.size() < n) {
buffer.write(io->read(n - buffer.size()));
}
}
QBuffer buffer;
QDataStream _stream;
};
TCPServer::TCPServer(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), SLOT(newConnection()));
qDebug() << "Listening:" << server->listen(QHostAddress::Any, 5404);
reverse_hash.insert("data1", 1);
reverse_hash.insert("data2", 2);
}
void TCPServer::newConnection()
{
while (server->hasPendingConnections())
{
qDebug()<<"incoming connection!";
socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), SLOT(disconnected()));
}
}
void TCPServer::disconnected()
{
qDebug() << "disconnected!";
disconnect(socket, SIGNAL(readyRead()));
disconnect(socket, SIGNAL(disconnected()));
socket->deleteLater();
}
void TCPServer::readyRead()
{
qDebug() << "Read!";
QString data;
BlockReader(socket).stream() >> data;
qDebug() <<"received data request: " << data;
switch(reverse_hash.value(data))
{
case 1: //call sequence to respond to request.(write to data)
qDebug() << "responding go data1 request!";
break;
case 2://call sequence to respond to request.(write to data)
qDebug() << "responding go data2 request!";
break;
}
BlockWriter(socket).stream()<<data;
socket->flush();
}
my client GUI class is as follows
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtNetwork>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QTcpSocket *socket;
QHash<int, QString> hash;
int current_slot, starting_slot, ending_slot;
signals:
void dataSet();
public slots:
void connectToHost();
void connected();
void disconnected();
void setDatatoGet();
void getData();
//bool writeData(QByteArray data);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
class BlockWriter
{
public:
BlockWriter(QIODevice *io)
{
buffer.open(QIODevice::WriteOnly);
this->io = io;
_stream.setVersion(QDataStream::Qt_4_8);
_stream.setDevice(&buffer);
_stream << quint64(0);
}
~BlockWriter()
{
_stream.device()->seek(0);
_stream << static_cast<quint64>(buffer.size());
io->write(buffer.buffer());
}
QDataStream &stream()
{
return _stream;
}
private:
QBuffer buffer;
QDataStream _stream;
QIODevice *io;
};
class BlockReader
{
public:
BlockReader(QIODevice *io)
{
buffer.open(QIODevice::ReadWrite);
_stream.setVersion(QDataStream::Qt_4_8);
_stream.setDevice(&buffer);
qint64 blockSize;
readMax(io, sizeof(blockSize));
buffer.seek(0);
_stream >> blockSize;
readMax(io, blockSize);
buffer.seek(sizeof(blockSize));
}
QDataStream& stream()
{
return _stream;
}
private:
void readMax(QIODevice *io, qint64 n)
{
while (buffer.size() < n) {
buffer.write(io->read(n - buffer.size()));
}
}
QBuffer buffer;
QDataStream _stream;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
starting_slot = 1;
current_slot = starting_slot;
ending_slot = 2;
ui->setupUi(this);
ui->status_label->setStyleSheet("background-color:red;");
ui->receive_btn->setEnabled(false);
socket = new QTcpSocket(this);
connectToHost();
connect(ui->conn_btn, SIGNAL(clicked()), this, SLOT(connectToHost()));
connect(ui->receive_btn, SIGNAL(clicked()), this, SLOT(setDatatoGet()));
connect(this, SIGNAL(dataSet()), this , SLOT(setDatatoGet()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::connectToHost()
{
socket->deleteLater();
socket = new QTcpSocket(this);
socket->connectToHost(QHostAddress("192.168.0.127"), 5404);
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
//ADD to hash table
hash.insert(1, "data1");
hash.insert(2, "data2");
}
void MainWindow::connected()
{
ui->status_label->setStyleSheet("background-color:green;");
ui->receive_btn->setEnabled(true);
connect(socket, SIGNAL(readyRead()),this, SLOT(getData()));
}
void MainWindow::disconnected()
{
ui->status_label->setStyleSheet("background-color:red;");
ui->receive_btn->setEnabled(false);
disconnect(socket, SIGNAL(readyRead()),this, SLOT(getData()));
}
void MainWindow::setDatatoGet()
{
if(current_slot == ending_slot + 1)
{
current_slot = starting_slot;
}
qDebug() <<"calling request data slot " << current_slot;
BlockWriter(socket).stream() << hash.value(current_slot);
socket->flush();
current_slot++;
}
void MainWindow::getData()
{
QString data;
BlockReader(socket).stream() >> data;
//qDebug() <<"received response, current received data is for slot "<< data <<"and current number is" << current_slot;
switch (current_slot - 1)
{
case 1:
//display in respective label
qDebug() << "display data1 to label!";
break;
case 2:
//display in respective label
qDebug() << "display data2 to label!";
break;
}
emit dataSet();
}
Upvotes: 0