Merge PR #143: TcpCommander: Fixed input and output device class

This commit is contained in:
Jenkins 2019-09-19 12:28:00 +02:00
commit 78bbf7f35b
9 changed files with 253 additions and 160 deletions

View File

@ -1,3 +1,34 @@
# TCP commander # TCP commander
This plugin is a generic approach to allow sending and receiving custom TCP packages in a network. This plugin is a generic approach to allow sending and receiving custom TCP packages.
> Note: This plugin is ment to be combined with a rule.
## TCP output
The TCP output opens a TCP connection to the given host IPv4 address and port everytime the output trigger gets activated. As soon
as the command has been executed the socket will close again. The connected state is only stated as connected
as long as the connection is active.
## TCP input
The TCP input creates a TCP server on the given port.
Be aware that only a single connection can be established simultaneously. The connected state is active as long as
a client is connected. It is up to the client to deside how long the connection stays active.
## Example
If you create a TCP Input on port 2323 and with the command `"Light 1 ON"`, following command will trigger an event in nymea and allows you to connect this event with a rule.
> Note: In this example nymea is running on `localhost`
$ echo "Light 1 ON" | nc localhost 2323
OK
If you create a TCP output on port 2324 and IP address 127.0.0.1, send in nymea the command `"Light 1 is ON"` and Netcat (nc) will receive and display your command.
> Note: the command is running on `localhost`
$ while :; do nc -l -p 2324; sleep 1; done
Light 1 is ON

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * *
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> * * Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* * * *
* This file is part of nymea. * * This file is part of nymea. *
* * * *
@ -26,14 +26,27 @@ DevicePluginTcpCommander::DevicePluginTcpCommander()
{ {
} }
Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device) Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device)
{ {
if (device->deviceClassId() == tcpOutputDeviceClassId) { if (device->deviceClassId() == tcpOutputDeviceClassId) {
QTcpSocket *tcpSocket = new QTcpSocket(this);
quint16 port = device->paramValue(tcpOutputDevicePortParamTypeId).toUInt();
QHostAddress address= QHostAddress(device->paramValue(tcpOutputDeviceIpv4addressParamTypeId).toString());
TcpSocket *tcpSocket = new TcpSocket(address, port, this);
m_tcpSockets.insert(tcpSocket, device); m_tcpSockets.insert(tcpSocket, device);
connect(tcpSocket, &QTcpSocket::connected, this, &DevicePluginTcpCommander::onTcpSocketConnected); connect(tcpSocket, &TcpSocket::connectionChanged, this, &DevicePluginTcpCommander::onTcpSocketConnectionChanged);
connect(tcpSocket, &QTcpSocket::disconnected, this, &DevicePluginTcpCommander::onTcpSocketDisconnected); connect(tcpSocket, &TcpSocket::commandSent, this, &DevicePluginTcpCommander::onTcpSocketCommandSent);
connect(tcpSocket, &QTcpSocket::bytesWritten, this, &DevicePluginTcpCommander::onTcpSocketBytesWritten); connect(tcpSocket, &TcpSocket::connectionTestFinished, this, [this, device] (bool status) {
if (status) {
emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess);
} else {
emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure);
}
});
tcpSocket->connectionTest();
// Test the socket, if a socket can be established the setup process was successfull
return Device::DeviceSetupStatusAsync; return Device::DeviceSetupStatusAsync;
} }
@ -43,8 +56,8 @@ Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device)
if (tcpServer->isValid()) { if (tcpServer->isValid()) {
m_tcpServer.insert(tcpServer, device); m_tcpServer.insert(tcpServer, device);
connect(tcpServer, &TcpServer::connected, this, &DevicePluginTcpCommander::onTcpServerConnected); connect(tcpServer, &TcpServer::connectionChanged, this, &DevicePluginTcpCommander::onTcpServerConnectionChanged);
connect(tcpServer, &TcpServer::disconnected, this, &DevicePluginTcpCommander::onTcpServerDisconnected); connect(tcpServer, &TcpServer::commandReceived, this, &DevicePluginTcpCommander::onTcpServerCommandReceived);
return Device::DeviceSetupStatusSuccess; return Device::DeviceSetupStatusSuccess;
} else { } else {
tcpServer->deleteLater(); tcpServer->deleteLater();
@ -60,11 +73,11 @@ Device::DeviceError DevicePluginTcpCommander::executeAction(Device *device, cons
if (device->deviceClassId() == tcpOutputDeviceClassId) { if (device->deviceClassId() == tcpOutputDeviceClassId) {
if (action.actionTypeId() == tcpOutputTriggerActionTypeId) { if (action.actionTypeId() == tcpOutputTriggerActionTypeId) {
int port = device->paramValue(tcpOutputDevicePortParamTypeId).toInt(); TcpSocket *tcpSocket = m_tcpSockets.key(device);
QHostAddress address= QHostAddress(device->paramValue(tcpOutputDeviceIpv4addressParamTypeId).toString()); QByteArray data = action.param(tcpOutputTriggerActionOutputDataAreaParamTypeId).value().toByteArray();
QTcpSocket *tcpSocket = m_tcpSockets.key(device); tcpSocket->sendCommand(data);
tcpSocket->connectToHost(address, port); m_pendingActions.insert(action.id(), device->id());
return Device::DeviceErrorNoError; return Device::DeviceErrorAsync;
} }
return Device::DeviceErrorActionTypeNotFound; return Device::DeviceErrorActionTypeNotFound;
} }
@ -76,11 +89,11 @@ void DevicePluginTcpCommander::deviceRemoved(Device *device)
{ {
if(device->deviceClassId() == tcpOutputDeviceClassId){ if(device->deviceClassId() == tcpOutputDeviceClassId){
QTcpSocket *tcpSocket = m_tcpSockets.key(device); TcpSocket *tcpSocket = m_tcpSockets.key(device);
m_tcpSockets.remove(tcpSocket); m_tcpSockets.remove(tcpSocket);
tcpSocket->deleteLater(); tcpSocket->deleteLater();
}else if(device->deviceClassId() == tcpInputDeviceClassId){ } else if(device->deviceClassId() == tcpInputDeviceClassId){
TcpServer *tcpServer = m_tcpServer.key(device); TcpServer *tcpServer = m_tcpServer.key(device);
m_tcpServer.remove(tcpServer); m_tcpServer.remove(tcpServer);
@ -89,105 +102,49 @@ void DevicePluginTcpCommander::deviceRemoved(Device *device)
} }
void DevicePluginTcpCommander::onTcpSocketConnected() void DevicePluginTcpCommander::onTcpSocketConnectionChanged(bool connected)
{ {
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender()); TcpSocket *tcpSocket = static_cast<TcpSocket *>(sender());
Device *device = m_tcpSockets.value(tcpSocket); Device *device = m_tcpSockets.value(tcpSocket);
if (device->deviceClassId() == tcpOutputDeviceClassId) { if (device->deviceClassId() == tcpOutputDeviceClassId) {
if (!device->setupComplete()) { device->setStateValue(tcpOutputConnectedStateTypeId, connected);
qDebug(dcTCPCommander()) << device->name() << "Setup finished" ;
emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess);
} else {
QByteArray data = device->paramValue(tcpOutputTriggerActionOutputDataAreaParamTypeId).toByteArray();
tcpSocket->write(data);
}
device->setStateValue(tcpOutputConnectedStateTypeId, true);
}
if (device->deviceClassId() == tcpInputDeviceClassId) {
if (!device->setupComplete()) {
qDebug(dcTCPCommander()) << device->name() << "Setup finished" ;
emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess);
}
device->setStateValue(tcpInputConnectedStateTypeId, true);
} }
} }
void DevicePluginTcpCommander::onTcpSocketCommandSent(bool successfull)
void DevicePluginTcpCommander::onTcpSocketDisconnected()
{ {
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender()); TcpSocket *tcpSocket = static_cast<TcpSocket *>(sender());
Device *device = m_tcpSockets.value(tcpSocket); Device *device = m_tcpSockets.value(tcpSocket);
if (device->deviceClassId() == tcpInputDeviceClassId) {
device->setStateValue(tcpInputConnectedStateTypeId, false); ActionId action = m_pendingActions.key(device->id());
} else if (device->deviceClassId() == tcpOutputDeviceClassId) { m_pendingActions.remove(action);
device->setStateValue(tcpOutputConnectedStateTypeId, false); if (successfull) {
emit actionExecutionFinished(action, Device::DeviceErrorNoError);
} else {
emit actionExecutionFinished(action, Device::DeviceErrorHardwareNotAvailable);
} }
} }
void DevicePluginTcpCommander::onTcpSocketBytesWritten() void DevicePluginTcpCommander::onTcpServerConnectionChanged(bool connected)
{
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender());
tcpSocket->close();
}
void DevicePluginTcpCommander::onTcpServerConnected()
{ {
TcpServer *tcpServer = static_cast<TcpServer *>(sender()); TcpServer *tcpServer = static_cast<TcpServer *>(sender());
Device *device = m_tcpServer.value(tcpServer); Device *device = m_tcpServer.value(tcpServer);
qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client connected" ; qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client connected" ;
if (device->deviceClassId() == tcpInputDeviceClassId) { if (device->deviceClassId() == tcpInputDeviceClassId) {
device->setStateValue(tcpInputConnectedStateTypeId, true); device->setStateValue(tcpInputConnectedStateTypeId, connected);
} else if (device->deviceClassId() == tcpOutputDeviceClassId) {
device->setStateValue(tcpOutputConnectedStateTypeId, true);
}
connect(tcpServer, &TcpServer::textMessageReceived, this, &DevicePluginTcpCommander::onTcpServerTextMessageReceived);
//send signal device Setup was successful
}
void DevicePluginTcpCommander::onTcpServerDisconnected()
{
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
Device *device = m_tcpServer.value(tcpServer);
qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client disconnected" ;
if (device->deviceClassId() == tcpInputDeviceClassId) {
device->setStateValue(tcpInputConnectedStateTypeId, false);
} else if (device->deviceClassId() == tcpOutputDeviceClassId) {
device->setStateValue(tcpOutputConnectedStateTypeId, false);
} }
} }
void DevicePluginTcpCommander::onTcpServerTextMessageReceived(QByteArray data) void DevicePluginTcpCommander::onTcpServerCommandReceived(QByteArray data)
{ {
TcpServer *tcpServer = static_cast<TcpServer *>(sender()); TcpServer *tcpServer = static_cast<TcpServer *>(sender());
Device *device = m_tcpServer.value(tcpServer); Device *device = m_tcpServer.value(tcpServer);
qDebug(dcTCPCommander()) << device->name() << "Message received" << data; qDebug(dcTCPCommander()) << device->name() << "Message received" << data;
device->setStateValue(tcpInputDataReceivedStateTypeId, data);
if (device->paramValue(tcpInputDeviceComparisionParamTypeId).toString() == "Is exactly") { Event event = Event(tcpInputTriggeredEventTypeId, device->id());
qDebug(dcTCPCommander()) << "is exactly"; ParamList params;
if (data == device->paramValue(tcpInputDeviceInputDataParamTypeId)) { params.append(Param(tcpInputTriggeredEventDataParamTypeId, data));
qDebug(dcTCPCommander()) << "comparison successful"; event.setParams(params);
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id())); emitEvent(event);
}
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId).toString() == "Contains") {
if (data.contains(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray())) {
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
}
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Contains not") {
if (!data.contains(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray()))
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Starts with") {
if (data.startsWith(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray()))
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Ends with") {
if (data.endsWith(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray()))
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
}
} }

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * *
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> * * Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* * * *
* This file is part of nymea. * * This file is part of nymea. *
* * * *
@ -23,6 +23,7 @@
#include "devices/deviceplugin.h" #include "devices/deviceplugin.h"
#include "tcpserver.h" #include "tcpserver.h"
#include "tcpsocket.h"
class DevicePluginTcpCommander : public DevicePlugin class DevicePluginTcpCommander : public DevicePlugin
{ {
@ -41,18 +42,16 @@ public:
Device::DeviceError executeAction(Device *device, const Action &action) override; Device::DeviceError executeAction(Device *device, const Action &action) override;
private: private:
QHash<QTcpSocket *, Device *> m_tcpSockets; QHash<TcpSocket *, Device *> m_tcpSockets;
QHash<TcpServer *, Device *> m_tcpServer; QHash<TcpServer *, Device *> m_tcpServer;
QHash<ActionId, DeviceId> m_pendingActions;
private slots: private slots:
void onTcpSocketConnected(); void onTcpSocketConnectionChanged(bool connected);
void onTcpSocketDisconnected(); void onTcpSocketCommandSent(bool successfulle);
void onTcpSocketBytesWritten();
void onTcpServerConnected();
void onTcpServerDisconnected();
void onTcpServerTextMessageReceived(QByteArray message);
void onTcpServerConnectionChanged(bool connected);
void onTcpServerCommandReceived(QByteArray message);
}; };
#endif // DEVICEPLUGINTCPCOMMANDER_H #endif // DEVICEPLUGINTCPCOMMANDER_H

View File

@ -4,9 +4,9 @@
"id": "741b7b0a-0c9c-4c93-be99-0d0bcf5a4643", "id": "741b7b0a-0c9c-4c93-be99-0d0bcf5a4643",
"vendors": [ "vendors": [
{ {
"name": "tcpCommander", "name": "nymea",
"displayName": "TCP Commander", "displayName": "nymea",
"id": "9181278e-7812-4a3e-a9ce-f00f3f8b8afd", "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
"deviceClasses": [ "deviceClasses": [
{ {
"id": "c67d059f-694f-47cb-8e1d-9e3e6d014c1a", "id": "c67d059f-694f-47cb-8e1d-9e3e6d014c1a",
@ -35,10 +35,10 @@
{ {
"id": "725b541a-9e0c-4634-81eb-e415c0b8f025", "id": "725b541a-9e0c-4634-81eb-e415c0b8f025",
"name": "connected", "name": "connected",
"displayName": "connected", "displayName": "Connected",
"type": "bool", "type": "bool",
"defaultValue": false, "defaultValue": false,
"displayNameEvent": "connection status changed" "displayNameEvent": "Connection status changed"
} }
], ],
"actionTypes": [ "actionTypes": [
@ -71,53 +71,23 @@
"displayName": "Port", "displayName": "Port",
"type": "int", "type": "int",
"defaultValue": "22" "defaultValue": "22"
},
{
"id": "d99f55c7-0e14-45ee-b0f0-33f2d1d2e674",
"name": "comparision",
"displayName": "Data Comparison",
"type": "QString",
"allowedValues": [
"Is exactly",
"Contains",
"Contains not",
"Starts with",
"Ends with"
],
"defaultValue": "Exactly"
},
{
"id": "23051bdf-3f50-41fa-abde-bc4fe0bcc4fc",
"name": "inputData",
"displayName": "Command",
"type": "QString",
"inputType": "TextArea",
"defaultValue": ""
} }
], ],
"stateTypes": [ "stateTypes": [
{ {
"id": "a2eb1619-261c-45ee-9587-6b5994633ad0", "id": "a2eb1619-261c-45ee-9587-6b5994633ad0",
"name": "connected", "name": "connected",
"displayName": "connected", "displayName": "Connected",
"type": "bool", "type": "bool",
"defaultValue": false, "defaultValue": false,
"displayNameEvent": "connection status changed" "displayNameEvent": "Connection status changed"
},
{
"id": "b98fdacc-59d7-41c4-b790-1fdca50dfb22",
"name": "dataReceived",
"displayName": "Data Received",
"type": "QString",
"defaultValue": "",
"displayNameEvent": "Data received"
} }
], ],
"eventTypes": [ "eventTypes": [
{ {
"id": "6d7c6df6-cb61-4d9e-b0d7-37c43911ca4b", "id": "6d7c6df6-cb61-4d9e-b0d7-37c43911ca4b",
"name": "triggered", "name": "triggered",
"displayName": "Command Received", "displayName": "Data recieved",
"paramTypes": [ "paramTypes": [
{ {
"id": "97d7ee8c-d9db-40b4-9855-4ceecd64c411", "id": "97d7ee8c-d9db-40b4-9855-4ceecd64c411",

View File

@ -7,8 +7,9 @@ TARGET = $$qtLibraryTarget(nymea_deviceplugintcpcommander)
SOURCES += \ SOURCES += \
deviceplugintcpcommander.cpp \ deviceplugintcpcommander.cpp \
tcpserver.cpp \ tcpserver.cpp \
tcpsocket.cpp
HEADERS += \ HEADERS += \
deviceplugintcpcommander.h \ deviceplugintcpcommander.h \
tcpserver.h \ tcpserver.h \
tcpsocket.h

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * *
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> * * Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* * * *
* This file is part of nymea. * * This file is part of nymea. *
* * * *
@ -23,28 +23,27 @@
#include <QNetworkInterface> #include <QNetworkInterface>
TcpServer::TcpServer(const QHostAddress address, const int &port, QObject *parent) : TcpServer::TcpServer(const QHostAddress address, const quint16 &port, QObject *parent) :
QObject(parent) QObject(parent)
{ {
m_tcpServer = new QTcpServer(this); m_tcpServer = new QTcpServer(this);
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection); connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
qDebug(dcTCPCommander()) << "TCP Server on Port: " << port << "Address: " << address.toString(); qDebug(dcTCPCommander()) << "TCP Server on Port: " << port << "Address: " << address.toString();
if (!m_tcpServer->listen(address, port)) { if (!m_tcpServer->listen(address, port)) {
qDebug(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString(); qWarning(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString();
return; return;
} }
} }
TcpServer::TcpServer(const int &port, QObject *parent) : TcpServer::TcpServer(const quint16 &port, QObject *parent) :
QObject(parent) QObject(parent)
{ {
m_tcpServer = new QTcpServer(this); m_tcpServer = new QTcpServer(this);
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection); connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
qDebug(dcTCPCommander()) << "TCP Server on Port: " << port; qDebug(dcTCPCommander()) << "TCP Server on Port: " << port;
if (!m_tcpServer->listen(QHostAddress::Any, port)) { if (!m_tcpServer->listen(QHostAddress::Any, port)) {
qDebug(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString(); qWarning(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString();
return; return;
} }
} }
@ -72,14 +71,13 @@ void TcpServer::newConnection()
{ {
qDebug(dcTCPCommander()) << "TCP Server new Connection request"; qDebug(dcTCPCommander()) << "TCP Server new Connection request";
m_socket = m_tcpServer->nextPendingConnection(); m_socket = m_tcpServer->nextPendingConnection();
m_socket->write("Hello client");
m_socket->flush(); m_socket->flush();
emit connected(); emit connectionChanged(true);
connect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected); connect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected);
connect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData); connect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData);
// Note: error signal will be interpreted as function, not as signal in C++11 // Note: error signal will be interpreted as function, not as signal in C++11
//connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
} }
@ -89,13 +87,18 @@ void TcpServer::onDisconnected()
disconnect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected); disconnect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected);
disconnect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData); disconnect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData);
m_socket->deleteLater(); m_socket->deleteLater();
emit disconnected(); emit connectionChanged(false);
} }
void TcpServer::readData() void TcpServer::readData()
{ {
QByteArray data = m_socket->readAll(); QByteArray data = m_socket->readAll();
qDebug(dcTCPCommander()) << "TCP Server data received: " << data; qDebug(dcTCPCommander()) << "TCP Server data received: " << data;
emit textMessageReceived(data); m_socket->write("OK\n");
emit commandReceived(data);
}
void TcpServer::onError(QAbstractSocket::SocketError error)
{
qWarning(dcTCPCommander()) << "Socket Error" << m_socket->errorString() << error;
} }

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * *
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> * * Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
* * * *
* This file is part of nymea. * * This file is part of nymea. *
* * * *
@ -29,8 +29,8 @@ class TcpServer : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit TcpServer(const QHostAddress address, const int &port, QObject *parent); explicit TcpServer(const QHostAddress address, const quint16 &port, QObject *parent = nullptr);
explicit TcpServer(const int &port, QObject *parent = 0); explicit TcpServer(const quint16 &port, QObject *parent = nullptr);
~TcpServer(); ~TcpServer();
bool isValid(); bool isValid();
@ -42,19 +42,19 @@ public:
private: private:
QTcpServer *m_tcpServer; QTcpServer *m_tcpServer = nullptr;
QTcpSocket *m_socket; QTcpSocket *m_socket = nullptr;
signals: signals:
void newPendingConnection(); void newPendingConnection();
void textMessageReceived(QByteArray message); void commandReceived(QByteArray message);
void connected(); void connectionChanged(bool connected);
void disconnected();
public slots: private slots:
void newConnection(); void newConnection();
void onDisconnected(); void onDisconnected();
void readData(); void readData();
void onError(QAbstractSocket::SocketError error);
}; };
#endif // TCPSERVER_H #endif // TCPSERVER_H

View File

@ -0,0 +1,93 @@
#include "tcpsocket.h"
#include "extern-plugininfo.h"
TcpSocket::TcpSocket(const QHostAddress address, const quint16 &port, QObject *parent) :
QObject(parent),
m_port(port),
m_address(address)
{
m_tcpSocket = new QTcpSocket(this);
connect(m_tcpSocket, &QTcpSocket::connected, this, &TcpSocket::onConnected);
connect(m_tcpSocket, &QTcpSocket::disconnected, this, &TcpSocket::onDisconnected);
connect(m_tcpSocket, &QTcpSocket::bytesWritten, this, &TcpSocket::onBytesWritten);
connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onTcpSocketError(QAbstractSocket::SocketError)));
}
void TcpSocket::sendCommand(QByteArray command)
{
if (m_pendingCommands.isEmpty()) {
m_pendingCommands.append(command);
m_tcpSocket->abort();
m_tcpSocket->connectToHost(m_address, m_port);
} else {
m_pendingCommands.append(command);
}
}
void TcpSocket::connectionTest()
{
QTcpSocket *testSocket = new QTcpSocket(this);
connect(testSocket, &QTcpSocket::connected, this,[this, testSocket] {
emit connectionTestFinished(true);
testSocket->deleteLater();
});
connect(testSocket, static_cast<void (QTcpSocket::*) (QAbstractSocket::SocketError)>(&QTcpSocket::error), this, [this, testSocket] {
emit connectionTestFinished(false);
testSocket->deleteLater();
});
testSocket->connectToHost(m_address, m_port);
}
void TcpSocket::onConnected()
{
qDebug(dcTCPCommander()) << "Socket connected" ;
if (!m_pendingCommands.isEmpty()) {
QByteArray data = m_pendingCommands.takeLast();
qDebug(dcTCPCommander()) << "Writing data:" << data;
m_tcpSocket->write(data + "\n");
} else {
m_tcpSocket->disconnectFromHost();
}
emit connectionChanged(true);
}
void TcpSocket::onDisconnected()
{
qDebug(dcTCPCommander()) << "Socket disconnected" ;
emit connectionChanged(false);
}
void TcpSocket::onBytesWritten()
{
emit commandSent(true);
if (!m_pendingCommands.isEmpty()){
m_tcpSocket->write(m_pendingCommands.takeFirst());
} else {
m_tcpSocket->close();
}
}
void TcpSocket::onError(QAbstractSocket::SocketError error)
{
qWarning(dcTCPCommander()) << "Socket Error" << m_tcpSocket->errorString();
switch (error) {
case QAbstractSocket::RemoteHostClosedError:
break;
case QAbstractSocket::HostNotFoundError:
break;
case QAbstractSocket::ConnectionRefusedError:
break;
default:
;
}
emit commandSent(false);
emit connectionChanged(false);
m_pendingCommands.clear(); //undefined socket state needs to clear command buffer.
if (m_tcpSocket->isOpen()) {
m_tcpSocket->disconnectFromHost();
}
}

39
tcpcommander/tcpsocket.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
#include <QObject>
#include <QTcpSocket>
#include <QHostAddress>
class TcpSocket : public QObject
{
Q_OBJECT
public:
explicit TcpSocket(const QHostAddress address, const quint16 &port, QObject *parent = nullptr);
void sendCommand(QByteArray command);
void connectionTest();
private:
QTcpSocket *m_tcpSocket = nullptr;
quint16 m_port;
QHostAddress m_address;
QList<QByteArray> m_pendingCommands;
signals:
void connectionChanged(bool connected);
void commandSent(bool successfull);
void connectionTestFinished(bool successfull);
private slots:
void onConnected();
void onDisconnected();
void onBytesWritten();
void onError(QAbstractSocket::SocketError error);
};
#endif // TCPSOCKET_H