命令模式是编程设计模式中的一种,这里介绍命令模式在Qt网络编程中的使用,讲述如何实现“一个类就是一个命令”的设计思想。
类图.png
本文福利, 免费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
commandabstract .h
- #ifndef COMMANDABSTRACT_H
- #define COMMANDABSTRACT_H
-
- #include
- #include
- class QTcpSocket;
- class CommandAbstract : public QObject
- {
- Q_OBJECT
- public:
- explicit CommandAbstract(QObject *parent = 0);
- //接口:准备要发送给服务器的数据
- //参数:cmdArgs用于传递要发送给服务器的数据(或叫做命令参数)
- //说明:在命令子类中实现该接口,并将命令参数保存到m_sendingData成员变量中
- //(m_sendingData为最终发送给服务器的数据)
- virtual void prepareSendingData(const QVariantHash& cmdArgs) = 0;
- //接口:解析来自服务器的响应数据,保存到m_parsedResponseData成员变量中
- //参数:data为从服务器读取到的响应数据
- //说明:在命令子类中实现该接口,每个网络命令都有不同的解析方式,因此这里抽象为接口
- virtual void parseResponseData(const QByteArray& data) = 0;
- //获取要发送给服务器的数据m_sendingData
- virtual QByteArray getSendingData() const;
- //设置要发送给服务器的数据m_sendingData
- virtual void setSendingData(const QByteArray& data);
- //执行命令,即:向服务器发送数据m_sendingData
- void exec();
- //设置QTcpSocket指针到命令类中,以实现网络通信功能
- void setTcpSocket(QTcpSocket* tcpSocket);
- //设置命令序列,记录命令编号,根据需要设置
- void setCmdIndex(int index);
- //设置命令操作类型(当相同的命令子类需要实现不同的功能时使用,如:当要使用相同的
- //命令子类发送不同的数据到服务器时,通过操作类型来区分服务器响应的数据)
- void setOperType(int operType);
- protected:
- int getCmdIndex() const;
- //获取命令操作类型
- int getCmdOperType() const;
- signals:
- //通过信号对外通知命令执行数据m_parsedResponseData
- void infoResultData(QVariantHash& parsedResponseData,QString& errorString);
- public slots:
- //当接收到网络数据响应时执行该槽函数
- void onReadyRead();
- private:
- QVariantHash m_cmdData;//命令参数
- QByteArray m_sendingData;//最终发送给服务器的命令数据
- QVariantHash m_parsedResponseData;//解析之后的服务器响应数据
- int m_cmdIndex;
- int m_cmdOperType;//命令操作类型
- QTcpSocket *m_tcpSocket;
-
- };
-
- #endif // COMMANDABSTRACT_H
-
commandabstract .cpp
- #include "commandabstract.h"
- #include <QTcpSocket>
- CommandAbstract::CommandAbstract(QObject *parent) :
- QObject(parent),
- m_cmdIndex(0),
- m_cmdOperType(0),
- m_tcpSocket(NULL)
- {
- }
- QByteArray CommandAbstract::getSendingData() const
- {
- return m_sendingData;
- }
- void CommandAbstract::setSendingData(const QByteArray &data)
- {
- m_sendingData = data;
- }
- void CommandAbstract::exec()
- {
- if(m_tcpSocket == NULL)
- return;
- m_tcpSocket->write(m_sendingData);
- }
- void CommandAbstract::setTcpSocket(QTcpSocket *tcpSocket)
- {
- m_tcpSocket = tcpSocket;
- connect(m_tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
- }
- void CommandAbstract::setCmdIndex(int index)
- {
- m_cmdIndex = index;
- }
- void CommandAbstract::setOperType(int operType)
- {
- m_cmdOperType = operType;
- }
- int CommandAbstract::getCmdIndex() const
- {
- return m_cmdIndex;
- }
- int CommandAbstract::getCmdOperType() const
- {
- return m_cmdOperType;
- }
- void CommandAbstract::onReadyRead()
- {
- QByteArray readData = m_tcpSocket->readAll();
- parseResponseData(readData);
- }
这里DemoCommand为命令子类,实际中可以根据需要派生出许多这样的子类向服务器发送不同的命令请求。DemoCommand类实现了基类中的两个接口函数。本例中,DemoCommand命令把数据key1和key2发送给服务程序,服务程序又将数据原样返回到客户端。
democommand.h
- #ifndef DEMOCOMMAND_H
- #define DEMOCOMMAND_H
- #include
- #include "commandabstract.h"
- class DemoCommand : public CommandAbstract
- {
- Q_OBJECT
- public:
- explicit DemoCommand(QObject *parent = 0);
- virtual void prepareSendingData(const QVariantHash& cmdArgs);
- virtual void parseResponseData(const QByteArray& data);
- };
- #endif // DEMOCOMMAND_H
democommand.cpp
- #include "democommand.h"
- #include <QDebug>
- #include <QJsonObject>
- #include <QJsonDocument>
- #include <QVariantHash>
- DemoCommand::DemoCommand(QObject *parent):CommandAbstract(parent)
- {
- }
- //把发送给服务器的数据key1和key2以json格式设置到命令基类中,共命令执行函数exec()使用
- void DemoCommand::prepareSendingData(const QVariantHash &cmdArgs)
- {
- QString data1 = cmdArgs.value("key1").toString();
- QString data2 = cmdArgs.value("key2").toString();
- QJsonObject jsonObj;
- jsonObj.insert("key1",data1);
- jsonObj.insert("key2",data2);
- QJsonDocument jsonDoc(jsonObj);
- this->setSendingData(jsonDoc.toJson());
- qDebug()<<"m_sendingData = "<<this->getSendingData();
- }
- //解析来自服务器的反馈数据,并通过信号发送到界面
- void DemoCommand::parseResponseData(const QByteArray &data)
- {
- //根据不同的操作类型,对服务器返回数据data进行解析
- qDebug()<<__LINE__<<__FUNCTION__<<"this->getCmdOperType() = "<<this->getCmdOperType();
- qDebug()<<__LINE__<<__FUNCTION__<<"Read data = "<<data;
- QVariantHash response;
- response.insert("response",data);
- emit this->infoResultData(response,QString());
- switch (this->getCmdOperType()) {
- case 1:{
-
- }break;
- case 2:{
-
- }break;
- case 3:{
-
- }break;
- default:
- break;
- }
- this->deleteLater();
- }
- void MainWindow::on_pushButtonSendCmd_clicked()
- {
- if(!m_tcpSocked->isOpen()){
- m_tcpSocked->connectToHost("127.0.0.1",9090);
- m_tcpSocked->waitForConnected();
- }
- QVariantHash cmdArgs;
- cmdArgs.insert("key1","data1");
- cmdArgs.insert("key2","data2");//data1和data2是模拟要发送给服务器的命令数据
- CommandAbstract* cmd = new DemoCommand();
- connect(cmd,SIGNAL(infoResultData(QVariantHash&,QString&)),this,SLOT(onInfoResultData(QVariantHash&,QString&)));
- cmd->setCmdIndex(1);
- cmd->setOperType(1);
- cmd->prepareSendingData(cmdArgs);
- cmd->setTcpSocket(m_tcpSocked);
- cmd->exec();
- }
- //接收来自服务器反馈的数据
- void MainWindow::onInfoResultData(QVariantHash &parsedResponseData, QString &errorString)
- {
- QString dataFromServer = parsedResponseData.value("response").toString();
- ui->textEdit->append(dataFromServer);
- }
客户程序.png
服务程序.png
本文福利, 免费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓