#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);
m_tcpServerTimer = new QTimer(this);
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);
}
void TCPSocketHelper::setHostAndePort(const QString &_Host,const int &_Port){
if(!getCloseFlag()){
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{
}
}
void TCPSocketHelper::closeTCPSocker(){
setCloseFlag(true);
m_TCPSocket->close();
m_ArrBuff.clear();
emit TCPSocketIsDisconnected();
if(m_LossCount != 0) m_LossCount = 0;
}
void TCPSocketHelper::openTCPSocket(){
setCloseFlag(false);
if(m_LossCount != 0) m_LossCount = 0;
setHostAndePort(m_ServerHost,m_ServerPort);
}
void TCPSocketHelper::checkHeartBeat(){
if(!getCloseFlag()){
if(getHeartBeatFlag()){
if(m_LossCount != 0){
emit TCPSocketUnstable();
m_LossCount = 0;
}
sendPing();
setHeartBeatFlag(false);
}else{
++m_LossCount;
if(m_LossCount > 6){
}
}
}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(){
m_tcpServerStatus = true;
m_HeartBeatTimer->start();
emit TCPSocketIsConnected();
}
void TCPSocketHelper::onDisconnected(){
closeTCPSocker();
m_tcpServerStatus = false;
m_tcpServerTimer->start(2000);
}
void TCPSocketHelper::onReadyRead(){
if(!getCloseFlag()){
m_ArrBuff.append(m_TCPSocket->readAll());
bool isOk = true;
while (isOk) {
QByteArray Arrtmp = getDataFrombuff(m_ArrBuff,isOk);
if(!Arrtmp.isEmpty()){
classifyByOPCode(Arrtmp);
}
}
}else{
}
}
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){
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:
ResponseData(MessageTypes::LatencyTest,syncID(Arr),Arr);
break;
case 10105:
ResponseInfoData(MessageTypes::ExchangeInfo,syncID(Arr),Arr);
break;
case 10129:
ResponseInfoData(MessageTypes::AllStockInfo,syncID(Arr),Arr);
break;
case 10134:
ResponseInfoData(MessageTypes::AllIndexInfo,syncID(Arr),Arr);
break;
case 10110:
ResponseData(MessageTypes::SingleStockQuotation,syncID(Arr),Arr);
break;
case 10111:
ResponseData(MessageTypes::multiStockQuotation,syncID(Arr),Arr);
break;
case 10107:
ResponseData(MessageTypes::SubscriptionStockPrice,syncID(Arr),Arr);
break;
case 10108:
ResponseData(MessageTypes::UnSubscriptionStockPrice,syncID(Arr),Arr);
break;
case 10113:
ResponseData(MessageTypes::KLineData_Offset,syncID(Arr),Arr);
break;
case 10122:
ResponseData(MessageTypes::KLineData_Time,syncID(Arr),Arr);
break;
case 10127:
ResponseData(MessageTypes::TransactionDetails,syncID(Arr),Arr);
break;
case 10117:
ResponseData(MessageTypes::TradingDay,syncID(Arr),Arr);
break;
case 10119:
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()){
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;
}
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{
return QByteArray();
}
}else{
static QByteArray ArrTemp;
static bool isOver = false;
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{
return QByteArray();
}
}
else{
return QByteArray();
}
}
}
void TCPSocketHelper::DebugOut(const QByteArray &,const QString &){
}
QByteArray TCPSocketHelper::getMaskingKey(const QByteArray& Arr){
return isMask(Arr) ? Arr.mid(2,4) : QByteArray();
}
TCPSocketHelper::~TCPSocketHelper(){
m_TCPSocket->deleteLater();
}
#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,
KLineData_Time,
TransactionDetails,
TradingDay,
TradingDayInterval,
rehabiData,
TotalRanking,
RealTimeQuotation,
ItemQuotation,
ConceptIndexInfo,
ConceptIndexLeaderboard,
ConceptIndexQuotation,
PCHomeIndexData,
UpAndDownDistribution,
MulticycleUpDown,
};
Q_ENUM(MessageTypes)
void setHostAndePort(const QString &m_ServerHost,const int &m_ServerPort);
void closeTCPSocker();
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;}
void sendPing();
void analyzeData(const QByteArray& Arr);
bool isValid(const QByteArray& Arr);
bool isEnd(const QByteArray& Arr);
bool isMask(const QByteArray& Arr);
bool isCMP(const QByteArray& Arr);
bool isRSV(const QByteArray& Arr);
char getOpCode(const QByteArray& Arr);
short businessID(const QByteArray& Arr);
short syncID(const QByteArray& Arr);
ushort getPayloadLen(const QByteArray& Arr);
QByteArray getMaskingKey(const QByteArray& Arr);
QByteArray getPayloadData(const QByteArray& Arrtmp);
QByteArray getDataFrombuff(QByteArray& Arr,bool &isOk);
void classifyByOPCode(const QByteArray& Arrtmp);
};
#endif