220 lines
6.9 KiB
C++
Executable File
220 lines
6.9 KiB
C++
Executable File
/**
|
|
* TcpSocket handling for MeteoDataUnit
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by hjl, SLSE, 2016-09-22
|
|
*/
|
|
|
|
#include "tcpsocket.h"
|
|
|
|
#include <QtCore/QTimer>
|
|
#include <QHostInfo>
|
|
//#include <sys/socket.h> // used for keepalive
|
|
//#include <netinet/tcp.h> // used for keepalive
|
|
//#include <netinet/in.h> // used for keepalive
|
|
|
|
|
|
namespace MeteoDataManagement
|
|
{
|
|
|
|
TcpSocket::TcpSocket(const char *logName, QObject *parent)
|
|
: QObject(parent)
|
|
, m_waitTime(1)
|
|
, m_socket(nullptr)
|
|
, m_tryReconnect(false)
|
|
, m_bSocketErrorWarnedOnce(false)
|
|
, m_logger(getLogger(logName))
|
|
{
|
|
DEBUG_LOG(m_logger) << "CTOR TCP-Socket... " ;
|
|
|
|
doConnect();
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
TcpSocket::~TcpSocket()
|
|
{
|
|
if (m_socket)
|
|
m_socket->close();
|
|
delete m_socket;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void TcpSocket::doConnect()
|
|
{
|
|
DEBUG_LOG(m_logger) << "doConnect TCP-Socket " ;
|
|
|
|
if (m_socket)
|
|
m_socket->deleteLater();
|
|
|
|
m_socket = new QTcpSocket(this);
|
|
connect(m_socket, &QTcpSocket::connected,
|
|
this, &TcpSocket::onConnected);
|
|
connect(m_socket, &QTcpSocket::disconnected,
|
|
this, &TcpSocket::onDisonnected);
|
|
connect(m_socket, &QTcpSocket::errorOccurred,
|
|
this, &TcpSocket::onError);
|
|
connect(m_socket, &QTcpSocket::readyRead,
|
|
this, &TcpSocket::onReadyRead);
|
|
|
|
if (m_tryReconnect)
|
|
{
|
|
INFO_LOG(m_logger) << "Try reconnect to host " << m_hostName
|
|
<< ":" << m_hostPort;
|
|
m_socket->connectToHost(m_hostName, m_hostPort);
|
|
}
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
void TcpSocket::start(const QString &hostName, quint16 port)
|
|
{
|
|
INFO_LOG(m_logger) << "Try connect to host: " << hostName
|
|
<< ": " << port;
|
|
|
|
m_hostName = hostName;
|
|
m_hostPort = port;
|
|
|
|
m_socket->connectToHost(m_hostName, port);
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
void TcpSocket::onConnected()
|
|
{
|
|
INFO_LOG(m_logger) << "Connected to "
|
|
<< m_socket->peerAddress().toString()
|
|
<< ":" << m_socket->peerPort();
|
|
m_bSocketErrorWarnedOnce = false;
|
|
m_waitTime = 1;
|
|
|
|
// Bei einer TCP Verbindung ergibt sich ein Problem bei der Pruefung ob die Verbindung noch besteht.
|
|
// Das sollte mit Hilfe des 'TCP keepalive Mechanismus' behoben werden.
|
|
// Infos dazu u.A. unter http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#intro
|
|
// Leider fuehrte keine der Varianten zum Erfolg.
|
|
// Der Abbruch wurde unabhaengig der Parameter in allen Faellen immer nach ziemlich genau 15:40Min dedektiert.
|
|
// Das Setzen der Systemvariablen war ebenfalls ohne Auswirkung.
|
|
// Da diese Programmteile unter Windows eh so nicht zu uebersetzen sind, ist der Codeteil hier in Kommentar gesetzt.
|
|
|
|
// INFO_LOG(m_logger) << "----Set TCP_KEEPIDLE parameter ";
|
|
|
|
// const int keepAliveOption = 1; // on
|
|
// if (setsockopt(m_socket->socketDescriptor(), SOL_SOCKET, SO_KEEPALIVE, &keepAliveOption, sizeof(keepAliveOption)) != 0)
|
|
// {
|
|
// ERROR_LOG(m_logger) << "Error setting SO_KEEPALIVE: " << errno;
|
|
// }
|
|
|
|
// const int idleTimeout = 5; // sec
|
|
// if (setsockopt(m_socket->socketDescriptor(), SOL_TCP, TCP_KEEPIDLE, &idleTimeout, sizeof(idleTimeout)) != 0)
|
|
// {
|
|
// ERROR_LOG(m_logger) << "Error setting TCP_KEEPIDLE: " << errno;
|
|
// }
|
|
|
|
// const int keepIntervalCnt = 10; // sec
|
|
// if (setsockopt(m_socket->socketDescriptor(), SOL_TCP, TCP_KEEPINTVL, &keepIntervalCnt, sizeof(keepIntervalCnt)) != 0)
|
|
// {
|
|
// ERROR_LOG(m_logger) << "Error setting TCP_KEEPINTVL: " << errno;
|
|
// }
|
|
|
|
// const int idlePaketCnt = 2; // 2 probes -> detection shoud be comes after 5s + 2 * 10s => 25 sec
|
|
// if (setsockopt(m_socket->socketDescriptor(), SOL_TCP, TCP_KEEPCNT, &idlePaketCnt, sizeof(idlePaketCnt)) != 0)
|
|
// {
|
|
// ERROR_LOG(m_logger) << "Error setting TCP_KEEPCNT: " << errno;
|
|
// }
|
|
|
|
// //----- Testausgaben
|
|
// int getOption = 0;
|
|
// socklen_t optlen = sizeof(getOption);
|
|
// getsockopt(m_socket->socketDescriptor(), SOL_SOCKET, SO_KEEPALIVE, &getOption, &optlen);
|
|
// ERROR_LOG(m_logger) << "...SO_KEEPALIVE set to: " << getOption;
|
|
|
|
// getsockopt(m_socket->socketDescriptor(), SOL_TCP, TCP_KEEPIDLE, &getOption, &optlen);
|
|
// ERROR_LOG(m_logger) << "...TCP_KEEPIDLE set to: " << getOption;
|
|
|
|
// getsockopt(m_socket->socketDescriptor(), SOL_TCP, TCP_KEEPINTVL, &getOption, &optlen);
|
|
// ERROR_LOG(m_logger) << "...TCP_KEEPINTVL set to: " << getOption;
|
|
|
|
// getsockopt(m_socket->socketDescriptor(), SOL_TCP, TCP_KEEPCNT, &getOption, &optlen);
|
|
// ERROR_LOG(m_logger) << "...TCP_KEEPCNT set to: " << getOption;
|
|
|
|
init(); // pure virtual function
|
|
// Auspraegung mit spezieller Sensorinitialisierung durchfuehren
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
void TcpSocket::onDisonnected()
|
|
{
|
|
INFO_LOG(m_logger) << "Disconnected from " << m_socket->peerAddress().toString()
|
|
<< ":" << m_socket->peerPort();
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
void TcpSocket::onError(QAbstractSocket::SocketError err)
|
|
{
|
|
ERROR_LOG(m_logger) << "Socket error: " << err
|
|
<< " \"" << m_socket->errorString() << "\""
|
|
<< " Hostname: " << m_hostName
|
|
<< " Serial Port:" << m_hostPort
|
|
<< " - trying to reconnect in " << m_waitTime << " seconds";
|
|
m_socket->disconnectFromHost();
|
|
|
|
// try reconnects ....
|
|
m_tryReconnect = true;
|
|
if (m_socket->state() != QAbstractSocket::UnconnectedState)
|
|
m_socket->waitForDisconnected();
|
|
|
|
m_waitTime += 2;
|
|
|
|
if (m_waitTime > 120)
|
|
m_waitTime = 120;
|
|
|
|
QTimer::singleShot(m_waitTime * 1000, this, &TcpSocket::doConnect);
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
void TcpSocket::onReadyRead()
|
|
{
|
|
// zeilenweises Einlesen der Sensordaten
|
|
while (m_socket->canReadLine())
|
|
{
|
|
const QByteArray line = m_socket->readLine();
|
|
DEBUG_LOG(m_logger) << "Read line from sensor: " << line;
|
|
|
|
dataAvailable(line); // pure virtual function
|
|
// Auspraegung mit spezieller Sensordatenauswertung durchfuehren
|
|
}
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
bool TcpSocket::sendCommand(const QByteArray &qba)
|
|
{
|
|
bool bOk = true;
|
|
|
|
INFO_LOG(m_logger) << "Send command: " << qba;
|
|
|
|
if (m_socket->state() != QTcpSocket::ConnectedState)
|
|
{
|
|
if (m_bSocketErrorWarnedOnce)
|
|
{
|
|
m_bSocketErrorWarnedOnce = true;
|
|
WARNING_LOG(m_logger) << "Error on sendCommand(). No socket connection estabilished."
|
|
<< " Hostname: " << m_hostName;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int trxBytes = m_socket->write(qba);
|
|
|
|
if (trxBytes != qba.size())
|
|
{
|
|
bOk = false;
|
|
ERROR_LOG(m_logger) << "Insufficient number of tansfered bytes."
|
|
<< " Soll: " << trxBytes << " Ist: " << qba.size();
|
|
}
|
|
m_socket->flush();
|
|
return bOk;
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
} // namespace MeteoDataManagement
|