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

master
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
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. *
* *
@ -26,14 +26,27 @@ DevicePluginTcpCommander::DevicePluginTcpCommander()
{
}
Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device)
{
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);
connect(tcpSocket, &QTcpSocket::connected, this, &DevicePluginTcpCommander::onTcpSocketConnected);
connect(tcpSocket, &QTcpSocket::disconnected, this, &DevicePluginTcpCommander::onTcpSocketDisconnected);
connect(tcpSocket, &QTcpSocket::bytesWritten, this, &DevicePluginTcpCommander::onTcpSocketBytesWritten);
connect(tcpSocket, &TcpSocket::connectionChanged, this, &DevicePluginTcpCommander::onTcpSocketConnectionChanged);
connect(tcpSocket, &TcpSocket::commandSent, this, &DevicePluginTcpCommander::onTcpSocketCommandSent);
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;
}
@ -43,8 +56,8 @@ Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device)
if (tcpServer->isValid()) {
m_tcpServer.insert(tcpServer, device);
connect(tcpServer, &TcpServer::connected, this, &DevicePluginTcpCommander::onTcpServerConnected);
connect(tcpServer, &TcpServer::disconnected, this, &DevicePluginTcpCommander::onTcpServerDisconnected);
connect(tcpServer, &TcpServer::connectionChanged, this, &DevicePluginTcpCommander::onTcpServerConnectionChanged);
connect(tcpServer, &TcpServer::commandReceived, this, &DevicePluginTcpCommander::onTcpServerCommandReceived);
return Device::DeviceSetupStatusSuccess;
} else {
tcpServer->deleteLater();
@ -60,11 +73,11 @@ Device::DeviceError DevicePluginTcpCommander::executeAction(Device *device, cons
if (device->deviceClassId() == tcpOutputDeviceClassId) {
if (action.actionTypeId() == tcpOutputTriggerActionTypeId) {
int port = device->paramValue(tcpOutputDevicePortParamTypeId).toInt();
QHostAddress address= QHostAddress(device->paramValue(tcpOutputDeviceIpv4addressParamTypeId).toString());
QTcpSocket *tcpSocket = m_tcpSockets.key(device);
tcpSocket->connectToHost(address, port);
return Device::DeviceErrorNoError;
TcpSocket *tcpSocket = m_tcpSockets.key(device);
QByteArray data = action.param(tcpOutputTriggerActionOutputDataAreaParamTypeId).value().toByteArray();
tcpSocket->sendCommand(data);
m_pendingActions.insert(action.id(), device->id());
return Device::DeviceErrorAsync;
}
return Device::DeviceErrorActionTypeNotFound;
}
@ -76,11 +89,11 @@ void DevicePluginTcpCommander::deviceRemoved(Device *device)
{
if(device->deviceClassId() == tcpOutputDeviceClassId){
QTcpSocket *tcpSocket = m_tcpSockets.key(device);
TcpSocket *tcpSocket = m_tcpSockets.key(device);
m_tcpSockets.remove(tcpSocket);
tcpSocket->deleteLater();
}else if(device->deviceClassId() == tcpInputDeviceClassId){
} else if(device->deviceClassId() == tcpInputDeviceClassId){
TcpServer *tcpServer = m_tcpServer.key(device);
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);
if (device->deviceClassId() == tcpOutputDeviceClassId) {
if (!device->setupComplete()) {
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);
device->setStateValue(tcpOutputConnectedStateTypeId, connected);
}
}
void DevicePluginTcpCommander::onTcpSocketDisconnected()
void DevicePluginTcpCommander::onTcpSocketCommandSent(bool successfull)
{
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender());
TcpSocket *tcpSocket = static_cast<TcpSocket *>(sender());
Device *device = m_tcpSockets.value(tcpSocket);
if (device->deviceClassId() == tcpInputDeviceClassId) {
device->setStateValue(tcpInputConnectedStateTypeId, false);
} else if (device->deviceClassId() == tcpOutputDeviceClassId) {
device->setStateValue(tcpOutputConnectedStateTypeId, false);
ActionId action = m_pendingActions.key(device->id());
m_pendingActions.remove(action);
if (successfull) {
emit actionExecutionFinished(action, Device::DeviceErrorNoError);
} else {
emit actionExecutionFinished(action, Device::DeviceErrorHardwareNotAvailable);
}
}
void DevicePluginTcpCommander::onTcpSocketBytesWritten()
{
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender());
tcpSocket->close();
}
void DevicePluginTcpCommander::onTcpServerConnected()
void DevicePluginTcpCommander::onTcpServerConnectionChanged(bool connected)
{
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
Device *device = m_tcpServer.value(tcpServer);
qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client connected" ;
if (device->deviceClassId() == tcpInputDeviceClassId) {
device->setStateValue(tcpInputConnectedStateTypeId, true);
} 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);
device->setStateValue(tcpInputConnectedStateTypeId, connected);
}
}
void DevicePluginTcpCommander::onTcpServerTextMessageReceived(QByteArray data)
void DevicePluginTcpCommander::onTcpServerCommandReceived(QByteArray data)
{
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
Device *device = m_tcpServer.value(tcpServer);
qDebug(dcTCPCommander()) << device->name() << "Message received" << data;
device->setStateValue(tcpInputDataReceivedStateTypeId, data);
if (device->paramValue(tcpInputDeviceComparisionParamTypeId).toString() == "Is exactly") {
qDebug(dcTCPCommander()) << "is exactly";
if (data == device->paramValue(tcpInputDeviceInputDataParamTypeId)) {
qDebug(dcTCPCommander()) << "comparison successful";
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
}
} 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()));
}
Event event = Event(tcpInputTriggeredEventTypeId, device->id());
ParamList params;
params.append(Param(tcpInputTriggeredEventDataParamTypeId, data));
event.setParams(params);
emitEvent(event);
}

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. *
* *
@ -23,6 +23,7 @@
#include "devices/deviceplugin.h"
#include "tcpserver.h"
#include "tcpsocket.h"
class DevicePluginTcpCommander : public DevicePlugin
{
@ -41,18 +42,16 @@ public:
Device::DeviceError executeAction(Device *device, const Action &action) override;
private:
QHash<QTcpSocket *, Device *> m_tcpSockets;
QHash<TcpSocket *, Device *> m_tcpSockets;
QHash<TcpServer *, Device *> m_tcpServer;
QHash<ActionId, DeviceId> m_pendingActions;
private slots:
void onTcpSocketConnected();
void onTcpSocketDisconnected();
void onTcpSocketBytesWritten();
void onTcpServerConnected();
void onTcpServerDisconnected();
void onTcpServerTextMessageReceived(QByteArray message);
void onTcpSocketConnectionChanged(bool connected);
void onTcpSocketCommandSent(bool successfulle);
void onTcpServerConnectionChanged(bool connected);
void onTcpServerCommandReceived(QByteArray message);
};
#endif // DEVICEPLUGINTCPCOMMANDER_H

View File

@ -4,9 +4,9 @@
"id": "741b7b0a-0c9c-4c93-be99-0d0bcf5a4643",
"vendors": [
{
"name": "tcpCommander",
"displayName": "TCP Commander",
"id": "9181278e-7812-4a3e-a9ce-f00f3f8b8afd",
"name": "nymea",
"displayName": "nymea",
"id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
"deviceClasses": [
{
"id": "c67d059f-694f-47cb-8e1d-9e3e6d014c1a",
@ -35,10 +35,10 @@
{
"id": "725b541a-9e0c-4634-81eb-e415c0b8f025",
"name": "connected",
"displayName": "connected",
"displayName": "Connected",
"type": "bool",
"defaultValue": false,
"displayNameEvent": "connection status changed"
"displayNameEvent": "Connection status changed"
}
],
"actionTypes": [
@ -71,53 +71,23 @@
"displayName": "Port",
"type": "int",
"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": [
{
"id": "a2eb1619-261c-45ee-9587-6b5994633ad0",
"name": "connected",
"displayName": "connected",
"displayName": "Connected",
"type": "bool",
"defaultValue": false,
"displayNameEvent": "connection status changed"
},
{
"id": "b98fdacc-59d7-41c4-b790-1fdca50dfb22",
"name": "dataReceived",
"displayName": "Data Received",
"type": "QString",
"defaultValue": "",
"displayNameEvent": "Data received"
"displayNameEvent": "Connection status changed"
}
],
"eventTypes": [
{
"id": "6d7c6df6-cb61-4d9e-b0d7-37c43911ca4b",
"name": "triggered",
"displayName": "Command Received",
"displayName": "Data recieved",
"paramTypes": [
{
"id": "97d7ee8c-d9db-40b4-9855-4ceecd64c411",

View File

@ -7,8 +7,9 @@ TARGET = $$qtLibraryTarget(nymea_deviceplugintcpcommander)
SOURCES += \
deviceplugintcpcommander.cpp \
tcpserver.cpp \
tcpsocket.cpp
HEADERS += \
deviceplugintcpcommander.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. *
* *
@ -23,28 +23,27 @@
#include <QNetworkInterface>
TcpServer::TcpServer(const QHostAddress address, const int &port, QObject *parent) :
TcpServer::TcpServer(const QHostAddress address, const quint16 &port, QObject *parent) :
QObject(parent)
{
m_tcpServer = new QTcpServer(this);
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
qDebug(dcTCPCommander()) << "TCP Server on Port: " << port << "Address: " << address.toString();
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;
}
}
TcpServer::TcpServer(const int &port, QObject *parent) :
TcpServer::TcpServer(const quint16 &port, QObject *parent) :
QObject(parent)
{
m_tcpServer = new QTcpServer(this);
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
qDebug(dcTCPCommander()) << "TCP Server on Port: " << 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;
}
}
@ -72,14 +71,13 @@ void TcpServer::newConnection()
{
qDebug(dcTCPCommander()) << "TCP Server new Connection request";
m_socket = m_tcpServer->nextPendingConnection();
m_socket->write("Hello client");
m_socket->flush();
emit connected();
emit connectionChanged(true);
connect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected);
connect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData);
// 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::readyRead, this, &TcpServer::readData);
m_socket->deleteLater();
emit disconnected();
emit connectionChanged(false);
}
void TcpServer::readData()
{
QByteArray data = m_socket->readAll();
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. *
* *
@ -29,8 +29,8 @@ class TcpServer : public QObject
{
Q_OBJECT
public:
explicit TcpServer(const QHostAddress address, const int &port, QObject *parent);
explicit TcpServer(const int &port, QObject *parent = 0);
explicit TcpServer(const QHostAddress address, const quint16 &port, QObject *parent = nullptr);
explicit TcpServer(const quint16 &port, QObject *parent = nullptr);
~TcpServer();
bool isValid();
@ -42,19 +42,19 @@ public:
private:
QTcpServer *m_tcpServer;
QTcpSocket *m_socket;
QTcpServer *m_tcpServer = nullptr;
QTcpSocket *m_socket = nullptr;
signals:
void newPendingConnection();
void textMessageReceived(QByteArray message);
void connected();
void disconnected();
void commandReceived(QByteArray message);
void connectionChanged(bool connected);
public slots:
private slots:
void newConnection();
void onDisconnected();
void readData();
void onError(QAbstractSocket::SocketError error);
};
#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