QT TCP断网失败重连

//#if _MSC_VER >= 1600
//#pragma execution_character_set("utf-8")
//#endif
#include "tcpsockethelper.h"
#include <QDebug>
#include <QDateTime>
#include "interface/typesconversionutils.h"
#include <QMetaEnum>
#include <QTimer>
#include <QMessageBox>

TCPSocketHelper::TCPSocketHelper(QObject *parent) : QObject(parent)
{
    m_TCPSocket = new QTcpSocket();
    m_HeartBeatTimer = new QTimer(this);
    m_HeartBeatTimer->setInterval(3000);                    //3秒进行一次心跳检测

    m_tcpServerTimer = new QTimer(this);
    //断开连接后,定时重连服务器(使用lambda表达式)
    connect(m_tcpServerTimer,&QTimer::timeout,[=](){
        if(m_tcpServerStatus == false){
            m_CloseFlag = false;
            setHostAndePort(m_ServerHost,m_ServerPort);
            qDebug()<<"/*----------m_tcpServerTimer---------"<<m_ServerHost<<m_ServerPort;
        }
    });


    connect(m_TCPSocket,&QTcpSocket::connected,this,&TCPSocketHelper::onConnected);
    connect(m_TCPSocket,&QTcpSocket::readyRead,this,&TCPSocketHelper::onReadyRead);
    connect(m_TCPSocket,&QTcpSocket::disconnected,this,&TCPSocketHelper::onDisconnected);
    connect(m_HeartBeatTimer, &QTimer::timeout, this, &TCPSocketHelper::checkHeartBeat);
}

//设置并启动 Socket
void TCPSocketHelper::setHostAndePort(const QString &_Host,const int &_Port){
    if(!getCloseFlag()){
//        qDebug()<<QDateTime::currentDateTime()<<"Socket set Host and Port"<<_Host<<_Port<<endl;
        m_ServerHost = _Host;
        m_ServerPort = quint16(_Port);
        qDebug()<<"/*-------setHostAndePort------"<<m_ServerHost<<m_ServerPort;

        m_TCPSocket->abort();       //重置套接字
        m_TCPSocket->connectToHost(m_ServerHost,m_ServerPort,QTcpSocket::ReadWrite);
    }else{
//        qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Error CloseFlag is On!!!";
    }
}

void TCPSocketHelper::closeTCPSocker(){
//    qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<endl;
    setCloseFlag(true);
    m_TCPSocket->close();       //关闭套接字
    m_ArrBuff.clear();//断开后清除缓存
    emit TCPSocketIsDisconnected();
    if(m_LossCount != 0) m_LossCount = 0;
}

void TCPSocketHelper::openTCPSocket(){
//    qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<endl;
    setCloseFlag(false);
    if(m_LossCount != 0) m_LossCount = 0;
    setHostAndePort(m_ServerHost,m_ServerPort);
}

void TCPSocketHelper::checkHeartBeat(){
    if(!getCloseFlag()){            //如果 Socket 不是主动断开
        if(getHeartBeatFlag()){     //获取心跳标志.如果为真,发送 ping,并置心跳标志为假
            if(m_LossCount != 0){
                emit TCPSocketUnstable();
//                qDebug()<<QDateTime::currentDateTime()<<"TCPSocketUnstable!!!!!!!!!!!!!!!";
                m_LossCount = 0;
            }
            sendPing();
            setHeartBeatFlag(false);
        }else{                      //如果心跳标志为假,说明没有收到对应的 pong,启动异常检测
            ++m_LossCount;
            if(m_LossCount > 6){
//                qDebug()<<QDateTime::currentDateTime()<<"m_LossCount:"<<m_LossCount;
            }
        }
    }else{                          //如果是主动断开,则关闭心跳计时器,并置心跳标志为真.
        if(m_HeartBeatTimer->isActive())
            m_HeartBeatTimer->stop(); //启动心跳检查,以保持连接
        setHeartBeatFlag(true);
    }
}

void TCPSocketHelper::sendPing(){
    QByteArray arrSend;
    arrSend.append(char(0x89));
    arrSend.append(TypesConversionUtils::UShortToByteArry(0));
    writeData(arrSend);
}

void TCPSocketHelper::onConnected(){
//    qDebug()<<Q_FUNC_INFO<<QDateTime::currentDateTime()<<"TcpSocket Connected!!!"<<endl;

    m_tcpServerStatus = true;
    m_HeartBeatTimer->start(); //连接后,启动心跳检查,以跟踪连接状态

    //确认此连接后,发送这个信号,如果后期添加多个地址,需要测速时,不要发送这个信号
    emit TCPSocketIsConnected();
}

void TCPSocketHelper::onDisconnected(){
//    qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"TcpSocket Disconnected  "<<"Error:"<<m_TCPSocket->error()<<"---"<<m_TCPSocket->errorString()<<endl;
    closeTCPSocker();//断开后关闭套接字
    m_tcpServerStatus = false;
    //2秒重连,重启重连服务器的定时器
    m_tcpServerTimer->start(2000);
}

void TCPSocketHelper::onReadyRead(){
    if(!getCloseFlag()){            //如果 Socket 不是主动断开
        m_ArrBuff.append(m_TCPSocket->readAll());                         //向缓冲区尾部追加数据
        bool isOk = true;
        while (isOk) {                                              //开始从缓冲区读取有效帧
            QByteArray Arrtmp = getDataFrombuff(m_ArrBuff,isOk);      //调用取帧函数,如果返回的数据不为空则为有效帧,如果 isOk 为真,则表示缓冲区中还可能包含有效帧
            if(!Arrtmp.isEmpty()){                                  //如果取出了有效帧
                classifyByOPCode(Arrtmp);
            }
        }
    }else{
//        qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Error CloseFlag is On!!!";
    }
}

void TCPSocketHelper::classifyByOPCode(const QByteArray& Arrtmp){
    if(getOpCode(Arrtmp) == 10){                        //如果这是一个心跳返回,则过滤
        setHeartBeatFlag(true);                         //置心跳标记为真
    }else{                                              //如果返回的数据为正常数据
        analyzeData(getPayloadData(Arrtmp));            //发送数据
    }
}

QByteArray TCPSocketHelper::getDataFrombuff(QByteArray &Arr,bool &isOk){
    if(Arr.size() >= 3){                                                //如果缓冲区的数据大于三个字节,最短有效字节数为 3,因为客户端不可能收到带有掩码的数据,为了整洁,去掉了掩码部分
        if(Arr.size() < (getPayloadLen(Arr) + 3)){                      //如果缓冲区中的数据不满一个有效帧
            isOk = false;                                               //不再执行查找有效帧的循环
            return QByteArray();                                        //并返回一个空数组
        }else{                                                          //如果缓冲区数据足够一个有效帧
            QByteArray dataArr = Arr.left(getPayloadLen(Arr) + 3);      //从缓冲区取完整的一帧
            if(isValid(dataArr)){                                       //如果取出的一帧是有效的
                Arr.remove(0,dataArr.size());                           //把这一帧从缓冲区移除
                isOk = Arr.size() < 3 ? false : true;                   //判断缓冲区中是否还有可能存在有效帧,如果存在,会继续执行循环,如果不存在不再执行
                return dataArr;                                         //返回有效帧
            }else{                                                      //如果这是一个无效帧,为未知的重大错误,尝试打印并报错,并从缓冲区移除此段数据
                QByteArray dataArr = Arr.left(getPayloadLen(Arr) + 3);      //从缓冲区取完整的一帧
                Arr.remove(0,dataArr.size());                               //移除
                isOk = Arr.size() < 3 ? false:true;                         //判断缓冲区中是否还有可能存在有效帧,如果存在,会继续执行循环,如果不存在不再执行
                DebugOut(dataArr,"**Err!!!! : dataArr Is Not Valid(!isMask(Arr))--TCPSocketHelper::getDataFrombuff");
                return QByteArray();
            }
        }
    }
    else{
        isOk = false;
        return QByteArray();
    }
}

//分发数据,有时间改成指针的吧....
void TCPSocketHelper::analyzeData(const QByteArray& Arr){
    if(Arr.isEmpty()){
        return;
    }
    switch (businessID(Arr)) {
    case 10133:
        ResponseData(MessageTypes::ItemQuotation,syncID(Arr),Arr);
        break;
    case 10101://LatencyTest,                 //服务器测速
        ResponseData(MessageTypes::LatencyTest,syncID(Arr),Arr);
        break;
    case 10105://ExchangeInfo,                //获取交易所信息  <--获取系统支持的交易所基本信息,交易所状态变更时推送消息
        ResponseInfoData(MessageTypes::ExchangeInfo,syncID(Arr),Arr);
        break;
    case 10129://AllStockInfo,                //获取股票信息
        ResponseInfoData(MessageTypes::AllStockInfo,syncID(Arr),Arr);
        break;
    case 10134://AllIndexInfo
        ResponseInfoData(MessageTypes::AllIndexInfo,syncID(Arr),Arr);
        break;
    case 10110://SingleStockQuotation,        //获取单个股票盘口报价
        ResponseData(MessageTypes::SingleStockQuotation,syncID(Arr),Arr);
        break;
    case 10111://multiStockQuotation,         //获取多个股票盘口报价
        ResponseData(MessageTypes::multiStockQuotation,syncID(Arr),Arr);
        break;
    case 10107://SubscriptionStockPrice,      //根据股票编号订阅行情
        ResponseData(MessageTypes::SubscriptionStockPrice,syncID(Arr),Arr);
        break;
    case 10108://UnSubscriptionStockPrice,    //根据股票编号取消订阅行情
        ResponseData(MessageTypes::UnSubscriptionStockPrice,syncID(Arr),Arr);
        break;
    case 10113://KLineData_Offset,            //K线数据--偏移量方式
        ResponseData(MessageTypes::KLineData_Offset,syncID(Arr),Arr);
        break;
    case 10122://KLineData_Time,              //K线数据--时间方式
        ResponseData(MessageTypes::KLineData_Time,syncID(Arr),Arr);
        break;
    case 10127://TransactionDetails,          //分笔明细
        ResponseData(MessageTypes::TransactionDetails,syncID(Arr),Arr);
        break;
    case 10117://TradingDay,                  //股票交易日
        ResponseData(MessageTypes::TradingDay,syncID(Arr),Arr);
        break;
    case 10119://TradingDayInterval
        ResponseData(MessageTypes::TradingDayInterval,syncID(Arr),Arr);
        break;
    case 10112:
        ResponseData(MessageTypes::IndexQuotation,syncID(Arr),Arr);
        break;
    case 10120://
        ResponseData(MessageTypes::StockSingleQuotationData,syncID(Arr),Arr);
        break;
    case 10123:
        ResponseData(MessageTypes::rehabiData,syncID(Arr),Arr);
        break;
    case 10130:
        ResponseData(MessageTypes::TotalRanking,syncID(Arr),Arr);
        break;
    case 10132:
        ResponseData(MessageTypes::RealTimeQuotation,syncID(Arr),Arr);
        break;
    case 10137:
        ResponseData(MessageTypes::ConceptIndexInfo,syncID(Arr),Arr);
        break;
    case 10138:
        ResponseData(MessageTypes::ConceptIndexLeaderboard,syncID(Arr),Arr);
        break;
    case 10139:
        ResponseData(MessageTypes::ConceptIndexQuotation,syncID(Arr),Arr);
        break;
    case 10140:
        ResponseData(MessageTypes::PCHomeIndexData,syncID(Arr),Arr);//接受消息
        break;
    case 10141:
        ResponseData(MessageTypes::UpAndDownDistribution,syncID(Arr),Arr);//接受消息
        break;
    case 10142:
        ResponseData(MessageTypes::MulticycleUpDown,syncID(Arr),Arr);//接受消息
        break;

    }
}

void TCPSocketHelper::requestData(const QByteArray& payloadData){
    if(m_TCPSocket->state() != QAbstractSocket::ConnectedState){
        return;
    }

    if(payloadData.size() > 1024 * 8){
        int count = payloadData.size() / (1024 * 8) + 1;
        for(int i = 0;i < count;i++){
            QByteArray arrSend;
            if(i == 0){//首帧
                arrSend.append(char(0x02));
                arrSend.append(TypesConversionUtils::UShortToByteArry(ushort(payloadData.mid(0,1024*8).size())));
                arrSend.append(payloadData.mid(0,1024*8));
            }else if(i == count - 1){//尾帧
                arrSend.append(char(0x80));
                arrSend.append(TypesConversionUtils::UShortToByteArry(ushort(payloadData.mid(1024*8*i).size())));
                arrSend.append(payloadData.mid(1024*8*i));
            }else{
                arrSend.append(char(0x00));//中间帧
                arrSend.append(TypesConversionUtils::UShortToByteArry(ushort(payloadData.mid(1024*8*i,1024*8).size())));
                arrSend.append(payloadData.mid(1024*8*i,1024*8));
            }
            writeData(arrSend);
        }
    }else{
        QByteArray arrSend;
        arrSend.append(char(0x82));
        arrSend.append(TypesConversionUtils::UShortToByteArry(ushort(payloadData.size())));
        arrSend.append(payloadData);
        writeData(arrSend);

        DebugOut(arrSend,"requestData");
    }
}

bool TCPSocketHelper::writeData(const QByteArray& Data){
    if(getCloseFlag()){            //如果 Socket 不是主动断开
//        qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Error CloseFlag is On!!!";
        return false;
    }

    bool flag_write = m_TCPSocket->write(Data) != -1;
    bool flag_flush = m_TCPSocket->flush();

    Q_ASSERT_X(flag_write && flag_flush,"","TCPSocketHelper's writeData() is Failed");

    return flag_write && flag_flush;

//    return (mSocket->write(Data) != -1) && (mSocket->flush());
}

bool TCPSocketHelper::isValid(const QByteArray& Arr){
    if(Arr.size() >= 3){
        if(isMask(Arr)){
            return getPayloadLen(Arr) == Arr.size() - 7;
        }else{
            return getPayloadLen(Arr) == Arr.size() - 3;
        }
    }
    else{
        return false;
    }
}

bool TCPSocketHelper::isEnd(const QByteArray& Arr){
    return ((Arr.at(0) >> 7) & 0x1) == 1;
}

bool TCPSocketHelper::isMask(const QByteArray& Arr){
    return ((Arr.at(0) >> 6) & 0x1) == 1;
}

bool TCPSocketHelper::isCMP(const QByteArray& Arr){
    return ((Arr.at(0) >> 5) & 0x1) == 1;
}

bool TCPSocketHelper::isRSV(const QByteArray& Arr){
    return ((Arr.at(0) >> 4) & 0x1) == 1;
}

char TCPSocketHelper::getOpCode(const QByteArray& Arr){
    return char(Arr.at(0) & 0x0f);
}

short TCPSocketHelper::syncID(const QByteArray& Arr){
    return TypesConversionUtils::ByteArrayToShort(Arr.left(2));
}
short TCPSocketHelper::businessID(const QByteArray& Arr){
    return TypesConversionUtils::ByteArrayToShort(Arr.mid(2,2));
}

ushort TCPSocketHelper::getPayloadLen(const QByteArray& Arr){
    return TypesConversionUtils::ByteArrayToUShort(Arr.mid(1,2));
}

QByteArray TCPSocketHelper::getPayloadData(const QByteArray& Arrtmp){
    if(isEnd(Arrtmp) && getOpCode(Arrtmp) != 0){                                        //如果是结束帧且不是一个后续帧,
        if(getOpCode(Arrtmp) == 2){                                                     //如果是一个二进制帧,暂时不会有其他种类,赶时间,多了再用枚举(心跳在上一层已经过滤掉了)
            if(isCMP(Arrtmp)){                                                          //如果这是一个压缩过的数据帧
                uint len = 10240;                                                       //制定一个足够大的缓冲区
                QByteArray tmp = TypesConversionUtils::UIntToByteArry(len, false);                //把缓冲区的大小赋给临时数组
                return qUncompress(tmp.append(Arrtmp.right(getPayloadLen(Arrtmp))));    //解压并返回数据
            }else{                                                                      //如果未压缩直接返回数据
                return Arrtmp.right(getPayloadLen(Arrtmp));
            }
        }else{                                                                           //报告错误,未定义的 OPCODE,并返回空数组
//            qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Err!! TCPSocketHelper::onReadyRead -->getOpCode Is Invalid AA"<<endl;
            return QByteArray();
        }
    }else{                                                                              //如果这是一个分帧的数据
        static QByteArray ArrTemp;                                                      //定义一个存储多个帧的静态变量
        static bool isOver = false;                                                     //判断分帧是否结束的biao'zhi标志
        static bool iscmp = true;
        if(!isEnd(Arrtmp) && getOpCode(Arrtmp) == 2)                                    //具有后继帧的首帧
        {
            iscmp = isCMP(Arrtmp);
            isOver = false;                                                             //标志置为假
            ArrTemp = Arrtmp.right(getPayloadLen(Arrtmp));                              //把帧中的有效数据传给存储多个帧的静态变量
        }
        else if(!isEnd(Arrtmp) && getOpCode(Arrtmp) == 0)                               //如果这是一个中间帧
        {
            isOver = false;                                                             //标志置为假
            ArrTemp.append(Arrtmp.right(getPayloadLen(Arrtmp)));                        //把帧中的有效数据附加到存储多个帧的静态变量
        }
        else if(isEnd(Arrtmp) && getOpCode(Arrtmp) == 0)                                //如果这是一个尾帧
        {
            isOver = true;                                                              //标志置为真
            ArrTemp.append(Arrtmp.right(getPayloadLen(Arrtmp)));
        }
        if(isOver){                                                                     //如果帧组合完毕了
            if(getOpCode(Arrtmp) == 0){                                                 //如果是一个二进制帧,暂时不会有其他种类,赶时间,多了再用枚举(心跳在上一层已经过滤掉了)
                if(iscmp){                                                      //如果是压缩过的数据
                    uint len = 1024000;                                                  //以下的同上
                    QByteArray tmp = TypesConversionUtils::UIntToByteArry(len, false);
                    return qUncompress(tmp.append(ArrTemp));;
                }else{
                    return ArrTemp;
                }
            } else{
//                qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Size:"<<ArrTemp.size();
//                qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Err!! TCPSocketHelper::onReadyRead -->getOpCode Is Invalid BB"<<endl;
                return QByteArray();
            }
        }
        else{
            return QByteArray();
        }
    }
}


void TCPSocketHelper::DebugOut(const QByteArray &/*dataArr*/,const QString &/*info*/){
//    qDebug()<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
//    qDebug()<<info;
//    qDebug()<<"**isValid:-------:"<<isValid(dataArr);
//    qDebug()<<"**isEnd:---------:"<<isEnd(dataArr);
//    qDebug()<<"**isMask:--------:"<<isMask(dataArr);
//    qDebug()<<"**isCMP:---------:"<<isCMP(dataArr);
//    qDebug()<<"**isRSV:---------:"<<isRSV(dataArr);
//    qDebug()<<"**getOpCode:-----:"<<getOpCode(getPayloadData(dataArr));
//    qDebug()<<"**businessID:----:"<<businessID(dataArr);
//    qDebug()<<"**getPayloadLen:-:"<<getPayloadLen(dataArr);
//    qDebug()<<"**getMaskingKey:-:"<<getMaskingKey(dataArr);
//    qDebug()<<"**arrSend size:--:"<<dataArr.size();
//    qDebug()<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
}

QByteArray TCPSocketHelper::getMaskingKey(const QByteArray& Arr){
    return isMask(Arr) ? Arr.mid(2,4) : QByteArray();
}

TCPSocketHelper::~TCPSocketHelper(){
    m_TCPSocket->deleteLater();
}

//#if _MSC_VER >= 1600
//#pragma execution_character_set("utf-8")
//#endif

#ifndef TCPSOCKET_H
#define TCPSOCKET_H

#include <QObject>
#include <QTcpSocket>
#include "shareHelper/SingletonTemplate/singleton.h"

class QTimer;
class TCPSocketHelper : public QObject
{
    Q_OBJECT
public:
    static TCPSocketHelper *getInstance(){
        return Singleton<TCPSocketHelper>::instance(TCPSocketHelper::createInstance);
    }
    ~TCPSocketHelper();

    using SocketState = QAbstractSocket::SocketState;
    enum MessageTypes {LatencyTest,                 //服务器测速
                       ExchangeInfo,                //获取交易所信息  <--获取系统支持的交易所基本信息,交易所状态变更时推送消息
                       AllStockInfo,                //获取股票信息
                       AllIndexInfo,                //获取指数信息
                       SingleStockQuotation,        //获取单个股票盘口报价
                       multiStockQuotation,         //获取多个股票盘口报价
                       StockSingleQuotationData,    //获取多个股票单个字段
                       IndexQuotation,         //获取多个指数盘口报价
                       SubscriptionStockPrice,      //根据股票编号订阅行情
                       UnSubscriptionStockPrice,    //根据股票编号取消订阅行情
                       KLineData_Offset,            //K线数据--偏移量方式
                       KLineData_Time,              //K线数据--时间方式
                       TransactionDetails,          //分笔明细
                       TradingDay,                  //股票交易日
                       TradingDayInterval,           //股票交易日区间
                       rehabiData,                   //复权因子
                       TotalRanking,                 //综合排名
                       RealTimeQuotation,                //盘口推送
                       ItemQuotation,
                       ConceptIndexInfo,
                       ConceptIndexLeaderboard,
                       ConceptIndexQuotation,
                       PCHomeIndexData,  //pc首页指数数据
                       UpAndDownDistribution,           //涨跌分布
                       MulticycleUpDown,      //多日涨幅
                      };
    Q_ENUM(MessageTypes)

    void setHostAndePort(const QString &m_ServerHost,const int &m_ServerPort);
    void closeTCPSocker();//TCPSocket 默认启动,用此函数可以停止 TCP 连接,它会直接关掉 Socket ,并置 isClose 为真,以关闭心跳检查,防止自动重连机制恢复连接.
    void openTCPSocket();
    SocketState getSocketStatus(){return m_TCPSocket->state();}

private slots:
    void onConnected();
    void onReadyRead();                   //负责接收数据,并缓存以及验证这些数据.
    void onDisconnected();
    void checkHeartBeat();                //心跳检查

public slots:
    void requestData(const QByteArray & );//写数据

signals:
    void ResponseData(MessageTypes,short,QByteArray);
    void ResponseInfoData(MessageTypes,short,QByteArray);
    void TCPSocketIsConnected();
    void TCPSocketIsDisconnected();
    void TCPSocketUnstable();

private:

    bool m_tcpServerStatus = true;
    QTimer *m_tcpServerTimer;

    static TCPSocketHelper* createInstance(){
        return new TCPSocketHelper();
    }

    TCPSocketHelper(QObject *parent = nullptr);
    QTcpSocket *m_TCPSocket = nullptr;
    QTimer *m_HeartBeatTimer;

    QString m_ServerHost;
    quint16 m_ServerPort;

    int m_LossCount = 0;
    bool m_heartbeatFlag = true;
    bool m_CloseFlag = false;
    QByteArray m_ArrBuff;

    bool writeData(const QByteArray& payloadData);

    //信息输出
    void DebugOut(const QByteArray &, const QString &);

    ///设置套接字关闭标志
    void setCloseFlag(bool _isClose){m_CloseFlag = _isClose;}

    ///获取套接字关闭标志
    bool getCloseFlag(){return m_CloseFlag;}

    ///心跳标记
    void setHeartBeatFlag(bool _Flag){m_heartbeatFlag = _Flag;}
    ///获取心跳标记
    bool getHeartBeatFlag(){return m_heartbeatFlag;}
    ///发送一个ping
    void sendPing();
    ///解析 payloaddata
    void analyzeData(const QByteArray& Arr);
    ///判断接受的数组是否有效(判断其长度)
    bool isValid(const QByteArray& Arr);

    ///判断此帧是否为结束帧 <-- FIN
    bool isEnd(const QByteArray& Arr);

    ///判断此帧是否有掩码处理,  1:需要处理(与maskingkey 异或)  0:不需要掩码处理。 <-- Mask
    bool isMask(const QByteArray& Arr);

    ///压缩格式报文(使用zlib压缩) 0:非压缩格式报文。如果数据被mask,则先unmask后再解压缩。 <-- CMP
    bool isCMP(const QByteArray& Arr);

    ///RSV: 1 bit  预留扩展位。<-- RSV
    bool isRSV(const QByteArray& Arr);

    ///获取 opcode ,(有待优化) <--- opcode
    char getOpCode(const QByteArray& Arr);

    ///获取信息的 businessID <-- businessID
    short businessID(const QByteArray& Arr);

    ///获取信息的 syncId <-- syncId
    short syncID(const QByteArray& Arr);

    ///获取数据长度 <-- Payload len
    ushort getPayloadLen(const QByteArray& Arr);

    ///获取 Masking-key ,如果Mask位设为1,此字段存在,否则缺失 <-- Masking-key
    QByteArray getMaskingKey(const QByteArray& Arr);

    ///获取长度为 PayloadLen 的字节数据 <-- payload data
    QByteArray getPayloadData(const QByteArray& Arrtmp);

    ///从缓存中读取一个数据帧,避免粘包,传入isOk的引用,用于判断其中是否还有有效的数据帧
    QByteArray getDataFrombuff(QByteArray& Arr,bool &isOk);

    ///按照 OPCode 分类
    void classifyByOPCode(const QByteArray& Arrtmp);
};

#endif // TCPSOCKET_H

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值