如何通过QTcp使用标准化的请求响应事务?

时间:2019-07-01 17:29:27

标签: c++ qt tcp qtcpsocket qtcpserver

我正在为放置在循环中的客户端创建服务器-客户端系统,以不断地从服务器查询预定的信息集。根据我对Qt框架的TCP实现如何工作的了解,我已经编写了一些代码,但是我不确定我编写的内容是否是正确的方法。


首先,我在客户端QTcp类中创建了带有一堆QByteArray变量的枚举,作为查询从客户端传递到服务器,如下所示

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

然后我制作一个函数,该函数需要一个枚举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信号以处理来自服务器的响应,并发送到函数,这些函数将根据{在相应的文本框中显示接收到的数据。 {1}}变量,如下所示

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

有人可以验证这是否是正确的方法,或者是否有更好的替代方法来处理任务。

1 个答案:

答案 0 :(得分:0)

使概念模型可以进行一些更改。使用this问题中“ 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();
}