Qt网络通信骨架解析,QtClient QtServer QtSerialPort

概述

老生常谈,为什么写这个骨架?通讯部分的代码繁杂,条理性差,是最主要的原因。平常的工程师对这块注意的不够。Qt当中通信组件就这么几个,他们都使用信号和槽机制代替了线程,接收的while循环就被信号和槽掩盖了。那么现在梳理下,这块怎么做。权当过去对Qt网络功能认识的升级版。经典的哦。

通信骨架

不使用Qt的时候,我们网络工程师经常缠绕在通讯件/协议/报文格式/网络功能定义之中,转着圈子不清晰的来回。现在这个骨架就是为了解决这个不明了不清晰。这里只介绍Tcp通信,Udp通信照本宣科。
骨架分析图如下
1. 通讯组件
2. 通讯协议
- 报文格式
- 功能定义
- 功能时序

通讯协议不依赖于通信组件。
通讯协议包含三个要素
遵循这几个特点制订了这套通讯骨架。

通讯组件

QtScocket,QtServer,QtSerialPort三个。他们的通信过程是同样的。
通过读数据槽接收流数据或者报文数据,对数据进行切分和分发。发送数据非常容易,write即可。

通讯协议

QtProtocol,虚基类提供协议定义,在所有的通信组件中都可以使用。这个虚基类定义了一组接口,splitter/dispatacher/maxlength/minlength/write信号等提供通讯组件设定的所需的协议接口。这个协议的突出特点是不依赖通讯组件。

通讯功能

用户通过此协议基类派生出特定的协议实现特定的功能。通讯组件安装特定协议,实现特定的通讯。

通讯报文

QtMessage,虚基类定义了报文格式,提供了packer和parser两个虚接口,通过派生报文,来提供通讯组件使用的报文格式。这个报文的突出特点是不依赖协议,从属于协议。

通讯结构体

这是用户最终发送和接收时使用的结构体,应用层直接使用结构体进行设定和读取操作。

工作过程

通讯组件安装通讯协议,
通讯协议提供通讯功能,自己选定使用的报文。

通讯例程

QtServer

qteserver.h

#ifndef QTESERVER_H
#define QTESERVER_H

#include <QTcpServer>
#include "qteprotocol.h"
#include "qteclient.h"

class QteServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit QteServer(QObject *parent = 0);
    ~QteServer();

    void installProtocol(QteProtocol* stack);
    void uninstallProtocol(QteProtocol* stack);
    QteProtocol* installedProtocol();

signals:
    // QTcpServer interface
protected:
    void incomingConnection(int handle);
private:
    QteProtocol* m_protocol;
};

qteserver.cpp

#include "qteserver.h"


QteServer::QteServer(QObject *parent) :
    QTcpServer(parent)
{
}

QteServer::~QteServer()
{
    close();
}

void QteServer::incomingConnection(int handle)
{
    QteClient* clientSocket = new QteClient(this);
    clientSocket->setSocketDescriptor(handle);
    connect(clientSocket, SIGNAL(disconnected()), clientSocket, SLOT(deleteLater()));
    clientSocket->installProtocol(m_protocol);
}

void QteServer::installProtocol(QteProtocol *stack)
{
    if(m_protocol)
        return;

    m_protocol = stack;
    connect(m_protocol, SIGNAL(write(const QByteArray&)), this, SLOT(write(const QByteArray&)));
}

void QteServer::uninstallProtocol(QteProtocol *stack)
{
    if(!m_protocol)
        return;

    disconnect(m_protocol, SIGNAL(write(const QByteArray&)), this, SLOT(write(const QByteArray&)));
    m_protocol = NULL;
}

QteProtocol *QteServer::installedProtocol()
{
    return m_protocol;
}

QtClient

qteclient.h

#ifndef QTE_CLIENT_H
#define QTE_CLIENT_H

#include <QTcpSocket>
#include "qteprotocol.h"
#include "QStringList"

#define _TCP_BLOCKDATA_SIZE                    0x400
#define _TCP_RECVBUFF_SIZE                      0x800

/**
 * @brief 客户端决定和协议的交互关系;只跟协议打交道;
 */
class QteClient : public QTcpSocket
{
    Q_OBJECT
public:
    explicit QteClient(QObject *parent = 0);
    virtual ~QteClient();

    void setServerIPAddress(QStringList ip) { m_serverIP = ip; }
    void setServerPort(quint32 p = 7000) { m_PORT = p; }

    void installProtocol(QteProtocol* stack);
    void uninstallProtocol(QteProtocol* stack);
    QteProtocol* installedProtocol();

    void SendConnectMessage();
    int SendDisConnectFromHost();

signals:
    void signalConnecting();
    void signalConnectSucc();
    void signalConnectFail();//
    void signalDisConnectSucc();//maybe
    void signalDisConnectFail();//?
    void signalUpdateProgress(int value);


private slots:
    void domainHostFound();
    void socketStateChanged(QAbstractSocket::SocketState);
    void socketErrorOccured(QAbstractSocket::SocketError);
    void socketConnected();
    void socketDisconnect();
    void updateProgress(qint64);

protected slots:
    void readyReadData();

private:
    void connectToSingelHost();

    //TODO:如果文件传输影响到了UI线程,那么需要将QTcpSocket局部变量化
    
  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值