#include "stpclient.h" stpClient::stpClient(QHostAddress address, int port, QObject *parent) : QObject{parent}, _state(stpClient_ns::stpState::DISCONNECTED), _pingState(stpClient_ns::pingState::IDLE), _socket(new QUdpSocket()), _address(address), _port(port), _pingTimer(new QTimer()), _pingTimeoutCount(0), _reconnectionTimer(new QTimer()) { _reconnectionTimer->setInterval(STP_RECONNECTION_PERIOD); QObject::connect(_reconnectionTimer, &QTimer::timeout, [=]{ connectToHost(); }); QObject::connect(_socket, &QUdpSocket::readyRead, this, [=](){ #ifdef STP_MANY_PACKETS_DEBUG int __count = 0; #endif while (_socket->hasPendingDatagrams()) { #ifdef STP_MANY_PACKETS_DEBUG __count++; #endif _processData(_socket->receiveDatagram()); } #ifdef STP_MANY_PACKETS_DEBUG if (__count > 44) qDebug() << "Received packets at once(!): " << __count; #endif }); _pingTimer->setTimerType(Qt::PreciseTimer); _pingTimer->setInterval(STP_PING_INTERVAL_MS); QObject::connect(_pingTimer, &QTimer::timeout, [=]{ if (_state == stpClient_ns::stpState::CONNECTED) { _socket->writeDatagram(_pack(stpProtocol_ns::packetType::PING), _address, _port); _pingState = stpClient_ns::pingState::PENDING; QTimer::singleShot(STP_TIMEOUT_MS, [=]{ if (_pingState == stpClient_ns::pingState::PENDING) { #ifdef STP_DEBUG qDebug() << QTime::currentTime().toString() << "ping timeout"; #endif _pingTimeoutCount++; if (_pingTimeoutCount >= STP_TIMEOUT_COUNT) { disconnectFromHost(); emit STP_disconnected(); } } }); } }); } stpClient::~stpClient() { delete _pingTimer; delete _reconnectionTimer; delete _socket; #ifdef STP_DEBUG qDebug() << "stpClient desctructor"; #endif } void stpClient::connectToHost() { if ((_state == stpClient_ns::stpState::DISCONNECTED) || (_state == stpClient_ns::stpState::CONNECTING)) { _socket->writeDatagram(_pack(stpProtocol_ns::packetType::SYNCReq), _address, _port); _state = stpClient_ns::stpState::CONNECTING; _reconnectionTimer->start(); } } void stpClient::disconnectFromHost() { if (_state != stpClient_ns::stpState::DISCONNECTED) { _socket->writeDatagram(_pack(stpProtocol_ns::packetType::RESET), _address, _port); _state = stpClient_ns::stpState::DISCONNECTED; _pingState = stpClient_ns::pingState::IDLE; _pingTimer->stop(); } } void stpClient::sendData(QByteArray *buff) { if (_state == stpClient_ns::stpState::CONNECTED) { _socket->writeDatagram(_pack(stpProtocol_ns::packetType::DATA, buff), _address, _port); } } QByteArray stpClient::_pack(stpProtocol_ns::packetType packetType, QByteArray *data) { QByteArray __result; if ( (packetType == stpProtocol_ns::packetType::DATA) && (data != nullptr) ) { // data packet trans_ns::bytes2word __size; __size.word = data->size(); __result.resize(CONST_HEADER_SIZE); __result[0] = packetType; __result[1] = __size.bytes.L; __result[2] = __size.bytes.H; __result.append(*data); } else { // system packets __result.resize(CONST_HEADER_SIZE); __result[0] = packetType; __result[1] = 0; __result[2] = 0; } return __result; } QByteArray stpClient::packIdRequest() { QByteArray __result; __result.resize(CONST_HEADER_SIZE + 1); __result[0] = stpProtocol_ns::packetType::DATA; __result[1] = 0x01; __result[2] = 0x00; __result[3] = (uint8_t)stpProtocol_ns::stpCommand::REQ_ID; return __result; } QByteArray stpClient::packIdSnRequest(uint16_t sn) { trans_ns::bytes2word __sn; __sn.word = sn; QByteArray __result; __result.resize(CONST_HEADER_SIZE + 3); __result[0] = stpProtocol_ns::packetType::DATA; __result[1] = 0x03; __result[2] = 0x00; __result[3] = (uint8_t)stpProtocol_ns::stpCommand::REQ_ID_SN; __result[4] = __sn.bytes.L; __result[5] = __sn.bytes.H; return __result; } void stpClient::_processData(QNetworkDatagram dg) { int __size = dg.data().size(); if (__size < CONST_HEADER_SIZE) return; QByteArray __header = dg.data().first(CONST_HEADER_SIZE); QByteArray __data = dg.data().last(__size - CONST_HEADER_SIZE); trans_ns::bytes2word __declaredSize; __declaredSize.bytes.L = __header[1]; __declaredSize.bytes.H = __header[2]; if (__data.size() != __declaredSize.word) { #ifdef STP_DEBUG qDebug() << dg.senderAddress().toString() << "badPacketSize (packetSize: " << __data.size() << "; declaredSize: " << __declaredSize.word << ")"; #endif return; } switch (__header[0]) { case stpProtocol_ns::packetType::PING: if (_state == stpClient_ns::stpState::CONNECTED) { _socket->writeDatagram(_pack(stpProtocol_ns::packetType::PONG), _address, _port); } else { _socket->writeDatagram(_pack(stpProtocol_ns::packetType::RESET), _address, _port); } break; case stpProtocol_ns::packetType::PONG: if (_pingState == stpClient_ns::pingState::PENDING) { _pingState = stpClient_ns::pingState::IDLE; _pingTimeoutCount = 0; } break; case stpProtocol_ns::packetType::DATA: emit STP_newDataPacketReceived(__data); break; case stpProtocol_ns::packetType::RESET: #ifdef STP_DEBUG qDebug() << "stp conection reset from: " << dg.senderAddress().toString(); #endif _state = stpClient_ns::stpState::DISCONNECTED; _pingState = stpClient_ns::pingState::IDLE; _pingTimer->stop(); emit STP_disconnected(); break; case stpProtocol_ns::packetType::SYNCAck: if (_state == stpClient_ns::stpState::CONNECTED) { #ifdef STP_DEBUG qDebug() << _address.toString() << "(!!!) came when client is already connected"; #endif } else { _state = stpClient_ns::stpState::CONNECTED; _pingTimer->start(); emit STP_connected(); } break; case stpProtocol_ns::packetType::SYNCReq: // клиент не реагирует break; } }