Как использовать стандартизированные транзакции ответа на запрос с использованием QTcp? - PullRequest
0 голосов
/ 01 июля 2019

Я делаю систему сервер-клиент для клиента, помещенного в цикл для непрерывного запроса заранее определенного набора информации с сервера .Я собрал немного кода из того, что я мог понять о том, как работает реализация TCP инфраструктуры Qt, но я не уверен, что написанное мной является правильным способом сделать это.


Сначала я сделал перечисление с кучей QByteArray переменных в клиентском классе QTcp для передачи в качестве запроса со стороны клиента на сервер, как показано ниже

enum datamap
{
    QByteArray data1 = 1;
    QByteArray data2 = 2;
    QByteArray data3 = 3;
    // and so on...
};

Затем я делаюфункция, которая принимает переменную enum datamap для передачи на сервер и переменную для хранения текущего запроса (чтобы избежать путаницы между данными, полученными для неправильного запроса), как показано ниже

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;
} 

После этого,Я создаю слот readyRead(), который подключается к сигналу readyread для обработки ответов от сервера и отправки в функции, которые будут отображать полученные данные в соответствующем текстовом поле на основе переменной current_request, как показано ниже

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....
}

Теперь для серверной части я создаю слот readyRead(), который подключается к сигналу readyread() от прослушивателя сокета, вызываемого функцией newConnection().

Это берет дескриптор от клиента и соответственно должен возвращать данные, связанные с дескриптором.Код для слота выглядит следующим образом:

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.....    
}

Может кто-нибудь проверить, правильно ли это сделать, или есть лучшая альтернатива для решения задачи.

1 Ответ

0 голосов
/ 03 июля 2019

Получил концептуальную модель для работы с несколькими изменениями. Использовал ответ, заданный "sashoalm" в этом вопросе, для передачи данных с использованием QdataStream и использовал сигналы и слоты для циклического переключения между последовательностью чтения-записи для каждого типа запроса.


мой класс сервера выглядит следующим образом

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();

}

мой класс GUI клиента выглядит следующим образом

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();
}


...