Commit 3b0f410b authored by Pavel Vainerman's avatar Pavel Vainerman

Перевод ModbusTCPServer и libev на использование TCPSocket

из commoncpp (ModbusTCPServer): сделал io-таймер (чтобы уйти от создания лишних потоков) Перенёс MBTCPPersistentSlave в MBSlave и удалил "отдельный" класс.
parent 62b4f673
...@@ -34,7 +34,7 @@ MBTCPServer::MBTCPServer(const std::unordered_set<ModbusAddr>& myaddr, const str ...@@ -34,7 +34,7 @@ MBTCPServer::MBTCPServer(const std::unordered_set<ModbusAddr>& myaddr, const str
cout << "(init): " cout << "(init): "
<< " addr: " << ia << ":" << port << endl; << " addr: " << ia << ":" << port << endl;
sslot = new ModbusTCPServerSlot(ia, port); sslot = new ModbusTCPServerSlot(ia, port);
// sslot->initLog(conf,name,logfile); // sslot->initLog(conf,name,logfile);
...@@ -53,9 +53,8 @@ MBTCPServer::MBTCPServer(const std::unordered_set<ModbusAddr>& myaddr, const str ...@@ -53,9 +53,8 @@ MBTCPServer::MBTCPServer(const std::unordered_set<ModbusAddr>& myaddr, const str
sslot->connectRemoteService( sigc::mem_fun(this, &MBTCPServer::remoteService) ); sslot->connectRemoteService( sigc::mem_fun(this, &MBTCPServer::remoteService) );
sslot->connectFileTransfer( sigc::mem_fun(this, &MBTCPServer::fileTransfer) ); sslot->connectFileTransfer( sigc::mem_fun(this, &MBTCPServer::fileTransfer) );
sslot->setRecvTimeout(6000); // sslot->setRecvTimeout(6000);
// sslot->setAfterSendPause(afterSend); // sslot->setReplyTimeout(10000);
sslot->setReplyTimeout(10000);
// build file list... // build file list...
} }
...@@ -74,29 +73,7 @@ void MBTCPServer::setLog(std::shared_ptr<DebugStream>& dlog ) ...@@ -74,29 +73,7 @@ void MBTCPServer::setLog(std::shared_ptr<DebugStream>& dlog )
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void MBTCPServer::execute() void MBTCPServer::execute()
{ {
// Работа... sslot->run( vaddr, false );
while(1)
{
ModbusRTU::mbErrCode res = sslot->receive( vaddr, UniSetTimer::WaitUpTime );
#if 0
// собираем статистику обмена
if( prev != ModbusRTU::erTimeOut )
{
// с проверкой на переполнение
askCount = askCount >= numeric_limits<long>::max() ? 0 : askCount + 1;
if( res != ModbusRTU::erNoError )
++errmap[res];
prev = res;
}
#endif
if( verbose && res != ModbusRTU::erNoError && res != ModbusRTU::erTimeOut )
cerr << "(execute::receive): " << ModbusRTU::mbErr2Str(res) << endl;
}
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void MBTCPServer::sigterm( int signo ) void MBTCPServer::sigterm( int signo )
......
...@@ -79,7 +79,6 @@ MBTCPTestServer::MBTCPTestServer( const std::unordered_set<ModbusAddr>& _vaddr, ...@@ -79,7 +79,6 @@ MBTCPTestServer::MBTCPTestServer( const std::unordered_set<ModbusAddr>& _vaddr,
sslot->connectFileTransfer( sigc::mem_fun(this, &MBTCPTestServer::fileTransfer) ); sslot->connectFileTransfer( sigc::mem_fun(this, &MBTCPTestServer::fileTransfer) );
sslot->setRecvTimeout(6000); sslot->setRecvTimeout(6000);
// sslot->setAfterSendPause(afterSend);
sslot->setReplyTimeout(10000); sslot->setReplyTimeout(10000);
// build file list... // build file list...
...@@ -114,32 +113,7 @@ void MBTCPTestServer::runThread() ...@@ -114,32 +113,7 @@ void MBTCPTestServer::runThread()
void MBTCPTestServer::execute() void MBTCPTestServer::execute()
{ {
isrunning = true; isrunning = true;
sslot->run( vaddr );
// cerr << "******************** MBTCPTestServer(" << myname << ") running... " << endl;
// Работа...
while(1)
{
ModbusRTU::mbErrCode res = sslot->receive( vaddr, UniSetTimer::WaitUpTime );
#if 0
// собираем статистику обмена
if( prev != ModbusRTU::erTimeOut )
{
// с проверкой на переполнение
askCount = askCount >= numeric_limits<long>::max() ? 0 : askCount + 1;
if( res != ModbusRTU::erNoError )
++errmap[res];
prev = res;
}
#endif
if( verbose && res != ModbusRTU::erNoError && res != ModbusRTU::erTimeOut )
cerr << "(execute::receive): " << ModbusRTU::mbErr2Str(res) << endl;
}
isrunning = false; isrunning = false;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include "UniSetObject.h" #include "UniSetObject.h"
#include "modbus/ModbusTypes.h" #include "modbus/ModbusTypes.h"
#include "modbus/ModbusServerSlot.h" #include "modbus/ModbusServerSlot.h"
#include "modbus/ModbusTCPServer.h"
#include "modbus/ModbusTCPServerSlot.h"
#include "PassiveTimer.h" #include "PassiveTimer.h"
#include "Trigger.h" #include "Trigger.h"
#include "Mutex.h" #include "Mutex.h"
...@@ -53,7 +55,8 @@ ...@@ -53,7 +55,8 @@
- \ref sec_MBSlave_ConfList - \ref sec_MBSlave_ConfList
- \ref sec_MBSlave_FileTransfer - \ref sec_MBSlave_FileTransfer
- \ref sec_MBSlave_MEIRDI - \ref sec_MBSlave_MEIRDI
- \ref sec_MBSlave_DIAG - \ref sec_MBSlave_DIAG
- \ref sec_MBSlave_TCP
\section sec_MBSlave_Comm Общее описание Modbus slave \section sec_MBSlave_Comm Общее описание Modbus slave
Класс реализует базовые функции для протокола Modbus в slave режиме. Реализацию Modbus RTU - см. RTUExchange. Класс реализует базовые функции для протокола Modbus в slave режиме. Реализацию Modbus RTU - см. RTUExchange.
...@@ -286,6 +289,16 @@ ...@@ -286,6 +289,16 @@
\section sec_MBSlave_DIAG Диагностические функции (0x08) \section sec_MBSlave_DIAG Диагностические функции (0x08)
\section sec_MBSlave_TCP Настройка TCPServer
\code
<MBTCPPersistentSlave ....sesscount="">
<clients>
<item ip="" respond="" invert="1" askcount=""/>
<item ip="" respond="" invert="1" askcount=""/>
<item ip="" respond="" invert="1" askcount=""/>
</clients>
</MBTCPPersistentSlave>
\endcode
*/ */
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -475,6 +488,8 @@ class MBSlave: ...@@ -475,6 +488,8 @@ class MBSlave:
void waitSMReady(); void waitSMReady();
virtual void execute_rtu(); virtual void execute_rtu();
virtual void execute_tcp(); virtual void execute_tcp();
virtual void updateStatistics();
virtual void updateTCPStatistics();
virtual bool activateObject() override; virtual bool activateObject() override;
virtual bool deactivateObject() override; virtual bool deactivateObject() override;
...@@ -565,6 +580,53 @@ class MBSlave: ...@@ -565,6 +580,53 @@ class MBSlave:
std::string logserv_host = {""}; std::string logserv_host = {""};
int logserv_port = {0}; int logserv_port = {0};
VMonitor vmon; VMonitor vmon;
// ----------------------------------------------------------------------------
// TCPServer section..
void initTCPClients( UniXML::iterator confnode );
timeout_t sessTimeout; /*!< таймаут на сессию */
timeout_t updateStatTime;
ModbusTCPServer::Sessions sess; /*!< список открытых сессий */
unsigned int sessMaxNum;
std::shared_ptr<ModbusTCPServerSlot> tcpserver;
struct ClientInfo
{
ClientInfo(): iaddr(""), respond_s(UniSetTypes::DefaultObjectId), invert(false),
askCount(0), askcount_s(UniSetTypes::DefaultObjectId)
{
ptTimeout.setTiming(0);
}
std::string iaddr;
UniSetTypes::ObjectId respond_s = { UniSetTypes::DefaultObjectId };
IOController::IOStateList::iterator respond_it;
bool invert = { false };
PassiveTimer ptTimeout;
timeout_t tout = { 2000 };
long askCount;
UniSetTypes::ObjectId askcount_s = { UniSetTypes::DefaultObjectId };
IOController::IOStateList::iterator askcount_it;
inline void initIterators( const std::shared_ptr<SMInterface>& shm )
{
shm->initIterator( respond_it );
shm->initIterator( askcount_it );
}
const std::string getShortInfo() const;
};
typedef std::unordered_map<std::string, ClientInfo> ClientsMap;
ClientsMap cmap;
UniSetTypes::ObjectId sesscount_id;
IOController::IOStateList::iterator sesscount_it;
std::atomic_bool tcpCancelled = { true };
}; };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#endif // _MBSlave_H_ #endif // _MBSlave_H_
......
// -----------------------------------------------------------------------------
#ifndef _MBTCPPersistentSlave_H_
#define _MBTCPPersistentSlave_H_
// -----------------------------------------------------------------------------
#include <unordered_map>
#include "MBSlave.h"
#include "modbus/ModbusTCPServer.h"
// -----------------------------------------------------------------------------
/*!
<MBTCPPersistentSlave ....sesscount="">
<clients>
<item ip="" respond="" invert="1" askcount=""/>
<item ip="" respond="" invert="1" askcount=""/>
<item ip="" respond="" invert="1" askcount=""/>
</clients>
</MBTCPPersistentSlave>
*/
// -----------------------------------------------------------------------------
/*! Реализация многоптоточного slave-интерфейса */
class MBTCPPersistentSlave:
public MBSlave
{
public:
MBTCPPersistentSlave( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, const std::shared_ptr<SharedMemory>& ic = nullptr, const std::string& prefix = "mbs" );
virtual ~MBTCPPersistentSlave();
/*! глобальная функция для инициализации объекта */
static std::shared_ptr<MBTCPPersistentSlave> init_mbslave( int argc, const char* const* argv,
UniSetTypes::ObjectId shmID, const std::shared_ptr<SharedMemory>& ic = nullptr,
const std::string& prefix = "mbs" );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, const char* const* argv );
UniSetTypes::SimpleInfo* getInfo( CORBA::Long userparam ) override;
protected:
virtual void execute_tcp() override;
virtual void initIterators() override;
virtual bool deactivateObject() override;
virtual void sigterm( int signo ) override;
timeout_t sessTimeout; /*!< таймаут на сессию */
timeout_t waitTimeout;
ModbusTCPServer::Sessions sess; /*!< список открытых сессий */
unsigned int sessMaxNum;
PassiveTimer ptUpdateInfo;
struct ClientInfo
{
ClientInfo(): iaddr(""), respond_s(UniSetTypes::DefaultObjectId), invert(false),
askCount(0), askcount_s(UniSetTypes::DefaultObjectId)
{
ptTimeout.setTiming(0);
}
std::string iaddr;
UniSetTypes::ObjectId respond_s = { UniSetTypes::DefaultObjectId };
IOController::IOStateList::iterator respond_it;
bool invert = { false };
PassiveTimer ptTimeout;
timeout_t tout = { 2000 };
long askCount;
UniSetTypes::ObjectId askcount_s = { UniSetTypes::DefaultObjectId };
IOController::IOStateList::iterator askcount_it;
inline void initIterators( const std::shared_ptr<SMInterface>& shm )
{
shm->initIterator( respond_it );
shm->initIterator( askcount_it );
}
const std::string getShortInfo() const;
};
typedef std::unordered_map<std::string, ClientInfo> ClientsMap;
ClientsMap cmap;
UniSetTypes::ObjectId sesscount_id;
IOController::IOStateList::iterator sesscount_it;
};
// -----------------------------------------------------------------------------
#endif // _MBTCPPersistentSlave_H_
// -----------------------------------------------------------------------------
bin_PROGRAMS = @PACKAGE@-mbslave @PACKAGE@-mbtcp-persistentslave bin_PROGRAMS = @PACKAGE@-mbslave
# не забывайте править версию в2.pc-файле # не забывайте править версию в2.pc-файле
UMBS_VER=@LIBVER@ UMBS_VER=@LIBVER@
...@@ -10,7 +10,7 @@ libUniSet2MBSlave_la_LIBADD = $(top_builddir)/lib/libUniSet2.la \ ...@@ -10,7 +10,7 @@ libUniSet2MBSlave_la_LIBADD = $(top_builddir)/lib/libUniSet2.la \
$(top_builddir)/extensions/lib/libUniSet2Extensions.la \ $(top_builddir)/extensions/lib/libUniSet2Extensions.la \
$(SIGC_LIBS) $(COMCPP_LIBS) $(SIGC_LIBS) $(COMCPP_LIBS)
libUniSet2MBSlave_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS) libUniSet2MBSlave_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
libUniSet2MBSlave_la_SOURCES = MBSlave.cc MBTCPPersistentSlave.cc libUniSet2MBSlave_la_SOURCES = MBSlave.cc
@PACKAGE@_mbslave_SOURCES = mbslave.cc @PACKAGE@_mbslave_SOURCES = mbslave.cc
@PACKAGE@_mbslave_LDADD = libUniSet2MBSlave.la $(top_builddir)/lib/libUniSet2.la \ @PACKAGE@_mbslave_LDADD = libUniSet2MBSlave.la $(top_builddir)/lib/libUniSet2.la \
...@@ -19,13 +19,6 @@ libUniSet2MBSlave_la_SOURCES = MBSlave.cc MBTCPPersistentSlave.cc ...@@ -19,13 +19,6 @@ libUniSet2MBSlave_la_SOURCES = MBSlave.cc MBTCPPersistentSlave.cc
$(SIGC_LIBS) $(COMCPP_LIBS) $(SIGC_LIBS) $(COMCPP_LIBS)
@PACKAGE@_mbslave_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS) @PACKAGE@_mbslave_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
@PACKAGE@_mbtcp_persistentslave_SOURCES = mbtcp-persistentslave.cc
@PACKAGE@_mbtcp_persistentslave_LDADD = libUniSet2MBSlave.la $(top_builddir)/lib/libUniSet2.la \
$(top_builddir)/extensions/SharedMemory/libUniSet2SharedMemory.la \
$(top_builddir)/extensions/lib/libUniSet2Extensions.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
@PACKAGE@_mbtcp_persistentslave_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
# install # install
devel_include_HEADERS = *.h devel_include_HEADERS = *.h
devel_includedir = $(pkgincludedir)/extensions devel_includedir = $(pkgincludedir)/extensions
......
...@@ -12,149 +12,171 @@ using namespace std; ...@@ -12,149 +12,171 @@ using namespace std;
// Read/write buffer max length // Read/write buffer max length
static const size_t MAX_BUF = 512; static const size_t MAX_BUF = 512;
typedef struct { typedef struct
struct event ev; {
char buf[MAX_BUF]; struct event ev;
size_t offset; char buf[MAX_BUF];
size_t size; size_t offset;
size_t size;
} ConnectionData; } ConnectionData;
void on_connect(int fd, short event, void *arg); void on_connect(int fd, short event, void* arg);
void client_read(int fd, short event, void *arg); void client_read(int fd, short event, void* arg);
void client_write(int fd, short event, void *arg); void client_write(int fd, short event, void* arg);
int main(int argc, char **argv) int main(int argc, char** argv)
{ {
// Check arguments // Check arguments
if (argc < 3) { if (argc < 3)
std::cout << "Run with options: <ip address> <port>" << std::endl; {
return 1; std::cout << "Run with options: <ip address> <port>" << std::endl;
} return 1;
// Create server socket }
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) { // Create server socket
std::cerr << "Failed to create socket" << std::endl; int server_sock = socket(AF_INET, SOCK_STREAM, 0);
return 1;
} if (server_sock == -1)
{
sockaddr_in sa; std::cerr << "Failed to create socket" << std::endl;
int on = 1; return 1;
char * ip_addr = argv[1]; }
short port = atoi(argv[2]);
sockaddr_in sa;
sa.sin_family = AF_INET; int on = 1;
sa.sin_port = htons(port); char* ip_addr = argv[1];
sa.sin_addr.s_addr = inet_addr(ip_addr); short port = atoi(argv[2]);
// Set option SO_REUSEADDR to reuse same host:port in a short time sa.sin_family = AF_INET;
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { sa.sin_port = htons(port);
std::cerr << "Failed to set option SO_REUSEADDR" << std::endl; sa.sin_addr.s_addr = inet_addr(ip_addr);
return 1;
} // Set option SO_REUSEADDR to reuse same host:port in a short time
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
// Bind server socket to ip:port {
if (bind(server_sock, reinterpret_cast<const sockaddr*>(&sa), sizeof(sa)) == -1) { std::cerr << "Failed to set option SO_REUSEADDR" << std::endl;
std::cerr << "Failed to bind server socket" << std::endl; return 1;
return 1; }
}
// Bind server socket to ip:port
// Make server to listen if (bind(server_sock, reinterpret_cast<const sockaddr*>(&sa), sizeof(sa)) == -1)
if (listen(server_sock, 10) == -1) { {
std::cerr << "Failed to make server listen" << std::endl; std::cerr << "Failed to bind server socket" << std::endl;
return 1; return 1;
} }
// Init events // Make server to listen
struct event evserver_sock; if (listen(server_sock, 10) == -1)
// Initialize {
event_init(); std::cerr << "Failed to make server listen" << std::endl;
// Set connection callback (on_connect()) to read event on server socket return 1;
event_set(&evserver_sock, server_sock, EV_READ|EV_PERSIST, on_connect, &evserver_sock); }
// Add server event without timeout
event_add(&evserver_sock, NULL); // Init events
struct event evserver_sock;
// Dispatch events // Initialize
event_dispatch(); event_init();
// Set connection callback (on_connect()) to read event on server socket
return 0; event_set(&evserver_sock, server_sock, EV_READ | EV_PERSIST, on_connect, &evserver_sock);
// Add server event without timeout
event_add(&evserver_sock, NULL);
// Dispatch events
event_dispatch();
return 0;
} }
// Handle new connection {{{ // Handle new connection {{{
void on_connect(int fd, short event, void *arg) void on_connect(int fd, short event, void* arg)
{ {
sockaddr_in client_addr; sockaddr_in client_addr;
socklen_t len = 0; socklen_t len = 0;
// Accept incoming connection
int sock = accept(fd, reinterpret_cast<sockaddr*>(&client_addr), &len);
// Accept incoming connection if (sock < 1)
int sock = accept(fd, reinterpret_cast<sockaddr*>(&client_addr), &len); {
if (sock < 1) { return;
return; }
}
cerr << "*** (ON CONNECT): ..." << endl; cerr << "*** (ON CONNECT): ..." << endl;
// Set read callback to client socket // Set read callback to client socket
ConnectionData * data = new ConnectionData; ConnectionData* data = new ConnectionData;
event_set(&data->ev, sock, EV_READ, client_read, data); event_set(&data->ev, sock, EV_READ, client_read, data);
// Reschedule server event // Reschedule server event
event_add(reinterpret_cast<struct event*>(arg), NULL); event_add(reinterpret_cast<struct event*>(arg), NULL);
// Schedule client event // Schedule client event
event_add(&data->ev, NULL); event_add(&data->ev, NULL);
} }
//}}} //}}}
// Handle client request {{{ // Handle client request {{{
void client_read(int fd, short event, void *arg) void client_read(int fd, short event, void* arg)
{ {
cerr << "*** (READ): RESCHEDULE..." << endl; cerr << "*** (READ): RESCHEDULE..." << endl;
ConnectionData * data = reinterpret_cast<ConnectionData*>(arg); ConnectionData* data = reinterpret_cast<ConnectionData*>(arg);
if (!data) {
close(fd); if (!data)
return; {
} close(fd);
int len = read(fd, data->buf, MAX_BUF - 1); return;
if (len < 1) { }
close(fd);
delete data; int len = read(fd, data->buf, MAX_BUF - 1);
return;
} if (len < 1)
data->buf[len] = 0; {
data->size = len; close(fd);
data->offset = 0; delete data;
// Set write callback to client socket return;
event_set(&data->ev, fd, EV_WRITE, client_write, data); }
// Schedule client event
event_add(&data->ev, NULL); data->buf[len] = 0;
data->size = len;
data->offset = 0;
// Set write callback to client socket
event_set(&data->ev, fd, EV_WRITE, client_write, data);
// Schedule client event
event_add(&data->ev, NULL);
} }
//}}} //}}}
// Handle client responce {{{ // Handle client responce {{{
void client_write(int fd, short event, void *arg) void client_write(int fd, short event, void* arg)
{ {
ConnectionData * data = reinterpret_cast<ConnectionData*>(arg); ConnectionData* data = reinterpret_cast<ConnectionData*>(arg);
if (!data) {
close(fd); if (!data)
return; {
} close(fd);
// Send data to client return;
int len = write(fd, data->buf + data->offset, data->size - data->offset); }
if (len < data->size - data->offset) {
// Failed to send rest data, need to reschedule // Send data to client
data->offset += len; int len = write(fd, data->buf + data->offset, data->size - data->offset);
event_set(&data->ev, fd, EV_WRITE, client_write, data);
// Schedule client event if (len < data->size - data->offset)
event_add(&data->ev, NULL); {
return; // Failed to send rest data, need to reschedule
} data->offset += len;
// close(fd); event_set(&data->ev, fd, EV_WRITE, client_write, data);
// delete data; // Schedule client event
event_add(&data->ev, NULL);
return;
}
// close(fd);
// delete data;
cerr << "*** (WRITE): RESCHEDULE..." << endl; cerr << "*** (WRITE): RESCHEDULE..." << endl;
event_set(&data->ev, fd, EV_READ, client_read, data); event_set(&data->ev, fd, EV_READ, client_read, data);
event_add(&data->ev, NULL); event_add(&data->ev, NULL);
} }
//}}} //}}}
#!/bin/sh
uniset2-start.sh -f ./uniset2-mbtcp-persistentslave --confile test.xml --dlog-add-levels any --mbs-log-add-levels any --mbs-exchangelog-add-levels any \
--smemory-id SharedMemory \
--mbs-name MBMultiSlave1 --mbs-type TCP --mbs-inet-addr 127.0.0.1 --mbs-inet-port 2048 --mbs-reg-from-id 1 --mbs-my-addr 0x01 \
$*
# --mbs-force 1
#--mbs-reg-from-id 1 \
#--mbs-filter-field CAN2sender --mbs-filter-value SYSTSNode \
\ No newline at end of file
...@@ -38,6 +38,7 @@ static void InitTest() ...@@ -38,6 +38,7 @@ static void InitTest()
ost::InetAddress ia(addr.c_str()); ost::InetAddress ia(addr.c_str());
mb->setTimeout(2000); mb->setTimeout(2000);
REQUIRE_NOTHROW( mb->connect(ia, port) ); REQUIRE_NOTHROW( mb->connect(ia, port) );
msleep(5000);
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include "Extensions.h" #include "Extensions.h"
#include "RTUExchange.h" #include "RTUExchange.h"
#include "MBSlave.h" #include "MBSlave.h"
#include "MBTCPPersistentSlave.h"
#include "MBTCPMaster.h" #include "MBTCPMaster.h"
#include "SharedMemory.h" #include "SharedMemory.h"
//#include "UniExchange.h" //#include "UniExchange.h"
...@@ -209,35 +208,6 @@ int main( int argc, const char** argv ) ...@@ -209,35 +208,6 @@ int main( int argc, const char** argv )
act->add(unet); act->add(unet);
} }
// ------------- MBTCPMultiSlave --------------
for( unsigned int i = 0; i < MaxAddNum; i++ )
{
stringstream s;
s << "--add-mbmultislave";
if( i > 0 ) s << i;
bool add_mbslave = findArgParam(s.str(), argc, argv) != -1;
if( add_mbslave )
{
stringstream p;
p << "mbms";
if( i > 0 ) p << i;
dinfo << "(smemory-plus): add MBTCPMultiSlave(" << p.str() << ")" << endl;
auto mbs = MBTCPPersistentSlave::init_mbslave(argc, argv, shm->getId(), shm, p.str());
if( !mbs )
return 1;
act->add(mbs);
}
}
// --------------------------------------- // ---------------------------------------
// попытка решить вопрос с "зомби" процессами // попытка решить вопрос с "зомби" процессами
signal( SIGCHLD, on_sigchild ); signal( SIGCHLD, on_sigchild );
......
// -------------------------------------------------------------------------
#ifndef UTCPCore_H_
#define UTCPCore_H_
// -------------------------------------------------------------------------
#include <cc++/thread.h> // ..for timeout_t
// -------------------------------------------------------------------------
namespace UTCPCore
{
bool setKeepAliveParams( int sock, timeout_t timeout_sec = 5, int conn_keepcnt = 1, int keepintvl = 2 );
}
// -------------------------------------------------------------------------
#endif // UTCPCore_H_
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
#ifndef UTCPSocket_H_
#define UTCPSocket_H_
// -------------------------------------------------------------------------
#include <string>
#include <cc++/socket.h>
// -------------------------------------------------------------------------
class UTCPSocket:
public ost::TCPSocket
{
public:
// dup and accept...raw socket
UTCPSocket( int sock );
// hname = "host:port"
UTCPSocket(const std::string& hname, unsigned backlog = 5, unsigned mss = 536 );
UTCPSocket(const ost::IPV4Address& bind, ost::tpport_t port, unsigned backlog = 5, unsigned mss = 536 );
virtual ~UTCPSocket();
// set keepalive params
// return true if OK
bool setKeepAliveParams( timeout_t timeout_sec = 5, int conn_keepcnt = 1, int keepintvl = 2 );
/*!
* Enable/disable delaying packets (Nagle algorithm)
*
* @return true on success.
* @param enable disable Nagle algorithm when set to true.
*/
bool setNoDelay( bool enable );
void setCompletion( bool set )
{
ost::TCPSocket::setCompletion(set);
}
int getSocket();
// --------------------------------------------------------------------
// Пришлось вынести эти функции read/write[Data] в public
// т.к. они сразу "посылают" данные в канал, в отличие от operator<<
// который у TCPStream (или std::iostream?) буферизует их и из-за этого
// не позволяет работать с отправкой коротких сообщений
// --------------------------------------------------------------------
ssize_t writeData( const void* buf, size_t len, timeout_t t = 0 );
ssize_t readData( void* buf, size_t len, char separator = 0, timeout_t t = 0 );
protected:
void init( bool throwflag = false );
private:
};
// -------------------------------------------------------------------------
#endif // UTCPSocket_H_
// -------------------------------------------------------------------------
...@@ -55,8 +55,8 @@ class UTCPStream: ...@@ -55,8 +55,8 @@ class UTCPStream:
// который у TCPStream (или std::iostream?) буферизует их и из-за этого // который у TCPStream (или std::iostream?) буферизует их и из-за этого
// не позволяет работать с отправкой коротких сообщений // не позволяет работать с отправкой коротких сообщений
// -------------------------------------------------------------------- // --------------------------------------------------------------------
ssize_t writeData( const void* buf, size_t len, timeout_t t=0 ); ssize_t writeData( const void* buf, size_t len, timeout_t t = 0 );
ssize_t readData( void * buf,size_t len,char separator=0,timeout_t t=0 ); ssize_t readData( void* buf, size_t len, char separator = 0, timeout_t t = 0 );
int getSocket(); int getSocket();
......
...@@ -40,6 +40,7 @@ class ModbusRTUSlave: ...@@ -40,6 +40,7 @@ class ModbusRTUSlave:
} }
virtual void terminate() override; virtual void terminate() override;
virtual bool isAcive() override;
protected: protected:
......
...@@ -20,7 +20,10 @@ class ModbusServer ...@@ -20,7 +20,10 @@ class ModbusServer
void initLog( UniSetTypes::Configuration* conf, const std::string& name, const std::string& logfile = "" ); void initLog( UniSetTypes::Configuration* conf, const std::string& name, const std::string& logfile = "" );
void setLog( std::shared_ptr<DebugStream> dlog ); void setLog( std::shared_ptr<DebugStream> dlog );
inline std::shared_ptr<DebugStream> log(){ return dlog; } inline std::shared_ptr<DebugStream> log()
{
return dlog;
}
std::unordered_set<ModbusRTU::ModbusAddr> addr2vaddr( ModbusRTU::ModbusAddr& mbaddr ); std::unordered_set<ModbusRTU::ModbusAddr> addr2vaddr( ModbusRTU::ModbusAddr& mbaddr );
...@@ -110,6 +113,8 @@ class ModbusServer ...@@ -110,6 +113,8 @@ class ModbusServer
virtual void cleanupChannel() {} virtual void cleanupChannel() {}
virtual void terminate() {} virtual void terminate() {}
virtual bool isAcive() = 0;
protected: protected:
/*! Обработка запроса на чтение данных (0x01). /*! Обработка запроса на чтение данных (0x01).
......
...@@ -12,13 +12,13 @@ namespace ModbusTCPCore ...@@ -12,13 +12,13 @@ namespace ModbusTCPCore
{ {
// t - msec (сколько ждать) // t - msec (сколько ждать)
size_t readNextData( UTCPStream* tcp, std::queue<unsigned char>& qrecv, size_t max = 100, timeout_t t=10 ); size_t readNextData( UTCPStream* tcp, std::queue<unsigned char>& qrecv, size_t max = 100, timeout_t t = 10 );
size_t getNextData( UTCPStream* tcp, std::queue<unsigned char>& qrecv, unsigned char* buf, size_t len, timeout_t t=10 ); size_t getNextData( UTCPStream* tcp, std::queue<unsigned char>& qrecv, unsigned char* buf, size_t len, timeout_t t = 10 );
ModbusRTU::mbErrCode sendData(UTCPStream* tcp, unsigned char* buf, size_t len, timeout_t t=10 ); ModbusRTU::mbErrCode sendData(UTCPStream* tcp, unsigned char* buf, size_t len, timeout_t t = 10 );
// работа напрямую с сокетом // работа напрямую с сокетом
size_t readDataFD(int fd, std::queue<unsigned char>& qrecv, size_t max = 100, size_t attempts=1 ); size_t readDataFD(int fd, std::queue<unsigned char>& qrecv, size_t max = 100, size_t attempts = 1 );
size_t getDataFD( int fd, std::queue<unsigned char>& qrecv, unsigned char* buf, size_t len, size_t attempts=1 ); size_t getDataFD( int fd, std::queue<unsigned char>& qrecv, unsigned char* buf, size_t len, size_t attempts = 1 );
ModbusRTU::mbErrCode sendDataFD( int fd, unsigned char* buf, size_t len ); ModbusRTU::mbErrCode sendDataFD( int fd, unsigned char* buf, size_t len );
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <queue> #include <queue>
#include <cc++/socket.h> #include <cc++/socket.h>
#include <ev++.h> #include <ev++.h>
#include <sigc++/sigc++.h>
#include "Mutex.h" #include "Mutex.h"
#include "Debug.h" #include "Debug.h"
#include "Configuration.h" #include "Configuration.h"
...@@ -13,9 +14,16 @@ ...@@ -13,9 +14,16 @@
#include "ModbusTypes.h" #include "ModbusTypes.h"
#include "ModbusServer.h" #include "ModbusServer.h"
#include "ModbusTCPSession.h" #include "ModbusTCPSession.h"
#include "UTCPStream.h" #include "ThreadCreator.h"
#include "UTCPSocket.h"
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/*! ModbusTCP server */ /*! ModbusTCPServer
* Реализация сервера на основе libev. Подерживается "много" соединений (постоянных).
* Хоть класс и наследуется от ModbusServer на самом деле он не реализует его функции,
* каждое соединение обслуживается классом ModbusTCPSession.
* Но собственно реализаия функций одна на всех, это следует учитывать при реализации обработчиков,
* т.к.из многих "соединений" будут вызываться одни и теже обработатчики.
*/
class ModbusTCPServer: class ModbusTCPServer:
public ModbusServer public ModbusServer
{ {
...@@ -23,11 +31,13 @@ class ModbusTCPServer: ...@@ -23,11 +31,13 @@ class ModbusTCPServer:
ModbusTCPServer( ost::InetAddress& ia, int port = 502 ); ModbusTCPServer( ost::InetAddress& ia, int port = 502 );
virtual ~ModbusTCPServer(); virtual ~ModbusTCPServer();
/*! Однопоточная обработка (каждый запрос последовательно), с разрывом соединения в конце */ // функция receive пока не поддерживается...
virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t msecTimeout ) override; virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr, timeout_t msecTimeout ) override;
/*! Поддержка большого количества соединений (постоянных) */ /*! Запуск сервера
virtual void mainLoop( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr ); * \param thread - создавать ли отдельный поток
*/
void run( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, bool thread = false );
void setMaxSessions( unsigned int num ); void setMaxSessions( unsigned int num );
inline unsigned int getMaxSessions() inline unsigned int getMaxSessions()
...@@ -54,13 +64,7 @@ class ModbusTCPServer: ...@@ -54,13 +64,7 @@ class ModbusTCPServer:
return ignoreAddr; return ignoreAddr;
} }
void cleanInputStream(); virtual void terminate();
virtual void cleanupChannel() override
{
cleanInputStream();
}
virtual void terminate() override;
// Сбор статистики по соединениям... // Сбор статистики по соединениям...
struct SessionInfo struct SessionInfo
...@@ -84,41 +88,73 @@ class ModbusTCPServer: ...@@ -84,41 +88,73 @@ class ModbusTCPServer:
return port; return port;
} }
protected: virtual bool isAcive() override;
// -------------------------------------------------
// Таймер.
// Т.к. mainLoop() "бесконечный", то сделана возможность
// подключиться к сигналу "таймера", например для обновления статистики по сессиям
// \warning Следует иметь ввиду, что обработчик сигнала, должен быть максимально коротким
// т.к. на это время останавливается работа основного потока (mainLoop)
// -------------------------------------------------
typedef sigc::signal<void> TimerSignal;
TimerSignal signal_timer();
virtual void ioAccept(ev::io &watcher, int revents); void setTimer( timeout_t msec );
virtual ModbusRTU::mbErrCode pre_send_request( ModbusRTU::ModbusMessage& request ) override; inline timeout_t getTimer()
virtual ModbusRTU::mbErrCode post_send_request( ModbusRTU::ModbusMessage& request ) override; {
return tmTime;
}
// realisation (see ModbusServer.h) protected:
virtual size_t getNextData( unsigned char* buf, int len ) override;
virtual void setChannelTimeout( timeout_t msec ) override; virtual void mainLoop();
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override; virtual void ioAccept(ev::io& watcher, int revents);
void onTimer( ev::timer& t, int revents );
virtual ModbusRTU::mbErrCode tcp_processing( UTCPStream& tcp, ModbusTCP::MBAPHeader& mhead );
void sessionFinished( ModbusTCPSession* s ); void sessionFinished( ModbusTCPSession* s );
virtual size_t getNextData( unsigned char* buf, int len ) override
{
return 0;
}
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override
{
return ModbusRTU::erHardwareError;
}
/*! set timeout for receive data */
virtual void setChannelTimeout( timeout_t msec ) override {};
ost::tpport_t port = { 0 }; ost::tpport_t port = { 0 };
ost::InetAddress iaddr; ost::InetAddress iaddr;
std::string myname;
std::queue<unsigned char> qrecv; std::queue<unsigned char> qrecv;
ModbusTCP::MBAPHeader curQueryHeader; ModbusTCP::MBAPHeader curQueryHeader;
typedef std::list<ModbusTCPSession*> SessionList;
UniSetTypes::uniset_mutex sMutex; UniSetTypes::uniset_mutex sMutex;
typedef std::list<ModbusTCPSession*> SessionList;
SessionList slist; SessionList slist;
bool ignoreAddr = { false }; bool ignoreAddr = { false };
unsigned int maxSessions = { 5 }; unsigned int maxSessions = { 100 };
unsigned int sessCount = { 0 }; unsigned int sessCount = { 0 };
timeout_t sessTimeout = { 10000 }; // msec timeout_t sessTimeout = { 10000 }; // msec
ev::default_loop* evloop = { 0 }; std::shared_ptr<ev::default_loop> evloop;
ev::io io; ev::io io;
int sock = { -1 }; std::shared_ptr<UTCPSocket> sock;
ev::timer ioTimer;
const std::unordered_set<ModbusRTU::ModbusAddr>* vmbaddr; const std::unordered_set<ModbusRTU::ModbusAddr>* vmbaddr;
std::shared_ptr< ThreadCreator<ModbusTCPServer> > thrMainLoop;
TimerSignal m_timer_signal;
timeout_t tmTime_msec = { TIMEOUT_INF }; // время по умолчанию для таймера (TimerSignal)
double tmTime = { 0.0 };
private: private:
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "ModbusServerSlot.h" #include "ModbusServerSlot.h"
#include "ModbusServer.h" #include "ModbusServer.h"
#include "PassiveTimer.h" #include "PassiveTimer.h"
#include "USocket.h"
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/*! /*!
* \brief The ModbusTCPSession class * \brief The ModbusTCPSession class
...@@ -36,13 +37,13 @@ class ModbusTCPSession: ...@@ -36,13 +37,13 @@ class ModbusTCPSession:
void cleanInputStream(); void cleanInputStream();
virtual void cleanupChannel() virtual void cleanupChannel() override
{ {
cleanInputStream(); cleanInputStream();
} }
virtual void terminate(); virtual void terminate() override;
virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t msecTimeout ); virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t msecTimeout ) override;
typedef sigc::slot<void, ModbusTCPSession*> FinalSlot; typedef sigc::slot<void, ModbusTCPSession*> FinalSlot;
...@@ -55,7 +56,10 @@ class ModbusTCPSession: ...@@ -55,7 +56,10 @@ class ModbusTCPSession:
return caddr; return caddr;
} }
void setSessionTimeout( double t );
void run(); void run();
virtual bool isAcive() override;
protected: protected:
...@@ -64,11 +68,11 @@ class ModbusTCPSession: ...@@ -64,11 +68,11 @@ class ModbusTCPSession:
// Buffer class - allow for output buffering such that it can be written out into async pieces // Buffer class - allow for output buffering such that it can be written out into async pieces
struct Buffer struct Buffer
{ {
unsigned char *data; unsigned char* data;
ssize_t len; ssize_t len;
ssize_t pos; ssize_t pos;
Buffer( const unsigned char *bytes, ssize_t nbytes ) Buffer( const unsigned char* bytes, ssize_t nbytes )
{ {
pos = 0; pos = 0;
len = nbytes; len = nbytes;
...@@ -81,7 +85,7 @@ class ModbusTCPSession: ...@@ -81,7 +85,7 @@ class ModbusTCPSession:
delete [] data; delete [] data;
} }
unsigned char *dpos() unsigned char* dpos()
{ {
return data + pos; return data + pos;
} }
...@@ -92,18 +96,18 @@ class ModbusTCPSession: ...@@ -92,18 +96,18 @@ class ModbusTCPSession:
} }
}; };
void callback( ev::io &watcher, int revents ); void callback( ev::io& watcher, int revents );
void idleCallback( ev::idle &watcher, int revents ); void onTimeout( ev::timer& watcher, int revents );
virtual void readEvent( ev::io &watcher ); virtual void readEvent( ev::io& watcher );
virtual void writeEvent( ev::io &watcher ); virtual void writeEvent( ev::io& watcher );
virtual void final(); virtual void final();
virtual size_t getNextData( unsigned char* buf, int len ) override; virtual size_t getNextData( unsigned char* buf, int len ) override;
virtual void setChannelTimeout( timeout_t msec ); virtual void setChannelTimeout( timeout_t msec );
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override; virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override;
virtual ModbusRTU::mbErrCode tcp_processing(ModbusTCP::MBAPHeader& mhead ); virtual ModbusRTU::mbErrCode tcp_processing(ModbusTCP::MBAPHeader& mhead );
virtual ModbusRTU::mbErrCode pre_send_request( ModbusRTU::ModbusMessage& request ); virtual ModbusRTU::mbErrCode pre_send_request( ModbusRTU::ModbusMessage& request ) override;
virtual ModbusRTU::mbErrCode post_send_request( ModbusRTU::ModbusMessage& request ); virtual ModbusRTU::mbErrCode post_send_request( ModbusRTU::ModbusMessage& request ) override;
virtual ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query, virtual ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query,
ModbusRTU::ReadCoilRetMessage& reply ); ModbusRTU::ReadCoilRetMessage& reply );
...@@ -156,9 +160,10 @@ class ModbusTCPSession: ...@@ -156,9 +160,10 @@ class ModbusTCPSession:
ModbusRTU::ModbusMessage buf; ModbusRTU::ModbusMessage buf;
ev::io io; ev::io io;
int sfd; std::shared_ptr<USocket> sock;
std::queue<Buffer*> qsend; std::queue<Buffer*> qsend;
ev::idle idle; ev::timer ioTimeout;
double sessTimeout = { 10.0 };
bool ignoreAddr = { false }; bool ignoreAddr = { false };
std::string peername = { "" }; std::string peername = { "" };
......
...@@ -185,3 +185,9 @@ void ModbusRTUSlave::terminate() ...@@ -185,3 +185,9 @@ void ModbusRTUSlave::terminate()
} }
catch(...) {} catch(...) {}
} }
// -------------------------------------------------------------------------
bool ModbusRTUSlave::isAcive()
{
return false;
}
// -------------------------------------------------------------------------
...@@ -20,7 +20,7 @@ using namespace std; ...@@ -20,7 +20,7 @@ using namespace std;
using namespace ModbusRTU; using namespace ModbusRTU;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
size_t ModbusTCPCore::readNextData(UTCPStream* tcp, size_t ModbusTCPCore::readNextData(UTCPStream* tcp,
std::queue<unsigned char>& qrecv, size_t max, timeout_t t ) std::queue<unsigned char>& qrecv, size_t max, timeout_t t )
{ {
if( !tcp || !tcp->isConnected() ) if( !tcp || !tcp->isConnected() )
return 0; return 0;
...@@ -32,7 +32,7 @@ size_t ModbusTCPCore::readNextData(UTCPStream* tcp, ...@@ -32,7 +32,7 @@ size_t ModbusTCPCore::readNextData(UTCPStream* tcp,
for( ; i < max; i++ ) for( ; i < max; i++ )
{ {
unsigned char c; unsigned char c;
ssize_t l = tcp->readData(&c, sizeof(c),0,t); ssize_t l = tcp->readData(&c, sizeof(c), 0, t);
if( l <= 0 ) if( l <= 0 )
break; break;
...@@ -80,7 +80,8 @@ size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size ...@@ -80,7 +80,8 @@ size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size
{ {
size_t i = 0; size_t i = 0;
#if 1 #if 1
for( size_t a=0; a<attempts; a++ )
for( size_t a = 0; a < attempts; a++ )
{ {
for( ; i < max; i++ ) for( ; i < max; i++ )
{ {
...@@ -94,19 +95,22 @@ size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size ...@@ -94,19 +95,22 @@ size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size
qrecv.push(c); qrecv.push(c);
} }
} }
#else #else
char* buf = new char[max]; char* buf = new char[max];
ssize_t l = 0; ssize_t l = 0;
for( size_t a=0; a<attempts; a++ )
for( size_t a = 0; a < attempts; a++ )
{ {
l = ::read(fd, buf, sizeof(buf)); l = ::read(fd, buf, sizeof(buf));
if( l > 0 ) if( l > 0 )
break; break;
} }
if( l > 0 ) if( l > 0 )
{ {
for( int i=0; i<l; i++ ) for( int i = 0; i < l; i++ )
qrecv.push(buf[i]); qrecv.push(buf[i]);
} }
...@@ -117,7 +121,7 @@ size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size ...@@ -117,7 +121,7 @@ size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
size_t ModbusTCPCore::getDataFD( int fd, std::queue<unsigned char>& qrecv, size_t ModbusTCPCore::getDataFD( int fd, std::queue<unsigned char>& qrecv,
unsigned char* buf, size_t len, size_t attempts ) unsigned char* buf, size_t len, size_t attempts )
{ {
if( qrecv.empty() || qrecv.size() < len ) if( qrecv.empty() || qrecv.size() < len )
{ {
...@@ -148,7 +152,8 @@ mbErrCode ModbusTCPCore::sendData( UTCPStream* tcp, unsigned char* buf, size_t l ...@@ -148,7 +152,8 @@ mbErrCode ModbusTCPCore::sendData( UTCPStream* tcp, unsigned char* buf, size_t l
try try
{ {
ssize_t l = tcp->writeData(buf,len,t); ssize_t l = tcp->writeData(buf, len, t);
if( l == len ) if( l == len )
return erNoError; return erNoError;
} }
...@@ -166,9 +171,11 @@ mbErrCode ModbusTCPCore::sendData( UTCPStream* tcp, unsigned char* buf, size_t l ...@@ -166,9 +171,11 @@ mbErrCode ModbusTCPCore::sendData( UTCPStream* tcp, unsigned char* buf, size_t l
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
mbErrCode ModbusTCPCore::sendDataFD( int fd, unsigned char* buf, size_t len ) mbErrCode ModbusTCPCore::sendDataFD( int fd, unsigned char* buf, size_t len )
{ {
ssize_t l = ::write(fd,buf,len); ssize_t l = ::write(fd, buf, len);
if( l == len ) if( l == len )
return erNoError; return erNoError;
return erHardwareError; return erHardwareError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -132,7 +132,7 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg, ...@@ -132,7 +132,7 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
{ {
if( tcp->isPending(ost::Socket::pendingOutput, timeout) ) if( tcp->isPending(ost::Socket::pendingOutput, timeout) )
{ {
tcp->writeData(&mh,sizeof(mh)); tcp->writeData(&mh, sizeof(mh));
// send PDU // send PDU
mbErrCode res = send(msg); mbErrCode res = send(msg);
......
...@@ -33,26 +33,44 @@ using namespace UniSetTypes; ...@@ -33,26 +33,44 @@ using namespace UniSetTypes;
ModbusTCPSession::~ModbusTCPSession() ModbusTCPSession::~ModbusTCPSession()
{ {
cancelled = true; cancelled = true;
if( io.is_active() ) if( io.is_active() )
io.stop(); io.stop();
if( idle.is_active() ) if( ioTimeout.is_active() )
idle.stop(); ioTimeout.stop();
if( sfd > 0 )
close(sfd);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusTCPSession::ModbusTCPSession(int sock, const std::unordered_set<ModbusAddr>& a, timeout_t timeout ): ModbusTCPSession::ModbusTCPSession( int sfd, const std::unordered_set<ModbusAddr>& a, timeout_t timeout ):
vaddr(a), vaddr(a),
timeout(timeout), timeout(timeout),
sfd(sock),
peername(""), peername(""),
caddr(""), caddr(""),
cancelled(false), cancelled(false),
askCount(0) askCount(0)
{ {
fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK); try
{
sock = make_shared<USocket>(sfd);
ost::tpport_t p;
ost::InetAddress iaddr = sock->getIPV4Peer(&p);
// resolve..
caddr = string( iaddr.getHostname() );
ostringstream s;
s << iaddr << ":" << p;
peername = s.str();
}
catch( const ost::SockException& ex )
{
ostringstream err;
err << ex.what();
dlog->crit() << "(ModbusTCPSession): err: " << err.str() << endl;
throw SystemError(err.str());
}
sock->setCompletion(false); // fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK);
setCRCNoCheckit(true); setCRCNoCheckit(true);
timeout_t tout = timeout / 1000; timeout_t tout = timeout / 1000;
...@@ -61,7 +79,7 @@ ModbusTCPSession::ModbusTCPSession(int sock, const std::unordered_set<ModbusAddr ...@@ -61,7 +79,7 @@ ModbusTCPSession::ModbusTCPSession(int sock, const std::unordered_set<ModbusAddr
tout = 3; tout = 3;
io.set<ModbusTCPSession, &ModbusTCPSession::callback>(this); io.set<ModbusTCPSession, &ModbusTCPSession::callback>(this);
idle.set<ModbusTCPSession, &ModbusTCPSession::idleCallback>(this); ioTimeout.set<ModbusTCPSession, &ModbusTCPSession::onTimeout>(this);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
unsigned int ModbusTCPSession::getAskCount() unsigned int ModbusTCPSession::getAskCount()
...@@ -69,22 +87,36 @@ unsigned int ModbusTCPSession::getAskCount() ...@@ -69,22 +87,36 @@ unsigned int ModbusTCPSession::getAskCount()
uniset_rwmutex_rlock l(mAsk); uniset_rwmutex_rlock l(mAsk);
return askCount; return askCount;
} }
void ModbusTCPSession::setSessionTimeout( double t )
{
sessTimeout = t;
if( ioTimeout.is_active() )
ioTimeout.start(t);
}
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPSession::run() void ModbusTCPSession::run()
{ {
if( dlog->is_info() ) if( dlog->is_info() )
dlog->info() << peername << "(run): run session.." << endl; dlog->info() << peername << "(run): run session.." << endl;
io.start(sfd, ev::READ); io.start(sock->getSocket(), ev::READ);
//idle.start(); ioTimeout.start(sessTimeout);
}
// -------------------------------------------------------------------------
bool ModbusTCPSession::isAcive()
{
return io.is_active();
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPSession::callback( ev::io &watcher, int revents ) void ModbusTCPSession::callback( ev::io& watcher, int revents )
{ {
if( EV_ERROR & revents ) if( EV_ERROR & revents )
{ {
if( dlog->is_crit() ) if( dlog->is_crit() )
dlog->crit() << peername << "(callback): EVENT ERROR.." << endl; dlog->crit() << peername << "(callback): EVENT ERROR.." << endl;
return; return;
} }
...@@ -97,25 +129,31 @@ void ModbusTCPSession::callback( ev::io &watcher, int revents ) ...@@ -97,25 +129,31 @@ void ModbusTCPSession::callback( ev::io &watcher, int revents )
if( qsend.empty() ) if( qsend.empty() )
io.set(ev::READ); io.set(ev::READ);
else else
io.set(ev::READ|ev::WRITE); io.set(ev::READ | ev::WRITE);
if( cancelled ) if( cancelled )
{ {
dlog->info() << peername << ": stop session... disconnect.." << endl; if( dlog->is_info() )
dlog->info() << peername << ": stop session... disconnect.." << endl;
io.stop(); io.stop();
//close(sfd); ioTimeout.stop();
idle.stop();
final(); final();
delete this; delete this;
} }
else
ioTimeout.start(sessTimeout); // restart timer..
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPSession::idleCallback(ev::idle& watcher, int revents) void ModbusTCPSession::onTimeout( ev::timer& watcher, int revents )
{ {
cerr << "idle..." << endl; if( dlog->is_info() )
dlog->info() << peername << ": timeout connection activity.." << endl;
terminate();
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPSession::readEvent( ev::io &watcher ) void ModbusTCPSession::readEvent( ev::io& watcher )
{ {
ModbusRTU::mbErrCode res = receive(vaddr, timeout); ModbusRTU::mbErrCode res = receive(vaddr, timeout);
...@@ -140,14 +178,17 @@ void ModbusTCPSession::writeEvent( ev::io& watcher ) ...@@ -140,14 +178,17 @@ void ModbusTCPSession::writeEvent( ev::io& watcher )
Buffer* buffer = qsend.front(); Buffer* buffer = qsend.front();
ssize_t ret = write(watcher.fd, buffer->dpos(), buffer->nbytes()); ssize_t ret = write(watcher.fd, buffer->dpos(), buffer->nbytes());
if( ret < 0 ) if( ret < 0 )
{ {
if( dlog->is_warn() ) if( dlog->is_warn() )
dlog->warn() << peername << "(writeEvent): write to socket error: " << strerror(errno) << endl; dlog->warn() << peername << "(writeEvent): write to socket error: " << strerror(errno) << endl;
return; return;
} }
buffer->pos += ret; buffer->pos += ret;
if( buffer->nbytes() == 0 ) if( buffer->nbytes() == 0 )
{ {
qsend.pop(); qsend.pop();
...@@ -229,20 +270,20 @@ void ModbusTCPSession::final() ...@@ -229,20 +270,20 @@ void ModbusTCPSession::final()
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::sendData( unsigned char* buf, int len ) mbErrCode ModbusTCPSession::sendData( unsigned char* buf, int len )
{ {
qsend.push( new Buffer(buf,len) ); qsend.push( new Buffer(buf, len) );
return erNoError; return erNoError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
size_t ModbusTCPSession::getNextData( unsigned char* buf, int len ) size_t ModbusTCPSession::getNextData( unsigned char* buf, int len )
{ {
ssize_t res = ModbusTCPCore::getDataFD( sfd, qrecv, buf, len ); ssize_t res = ModbusTCPCore::getDataFD( sock->getSocket(), qrecv, buf, len );
if( res > 0 ) if( res > 0 )
return res; return res;
if( res < 0 ) if( res < 0 )
{ {
if( errno!=EAGAIN && dlog->is_warn() ) if( errno != EAGAIN && dlog->is_warn() )
dlog->warn() << peername << "(getNextData): read from socket error(" << errno << "): " << strerror(errno) << endl; dlog->warn() << peername << "(getNextData): read from socket error(" << errno << "): " << strerror(errno) << endl;
return 0; return 0;
...@@ -295,12 +336,13 @@ mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead ) ...@@ -295,12 +336,13 @@ mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead )
return erInvalidFormat; return erInvalidFormat;
} }
len = ModbusTCPCore::readDataFD( sfd, qrecv, mhead.len ); len = ModbusTCPCore::readDataFD( sock->getSocket(), qrecv, mhead.len );
if( len == 0 ) if( len == 0 )
{ {
// делаем ещё одну попытку чтения через некоторое время // делаем ещё одну попытку чтения через некоторое время
msleep(5); msleep(5);
len = ModbusTCPCore::readDataFD( sfd, qrecv, mhead.len ); len = ModbusTCPCore::readDataFD( sock->getSocket(), qrecv, mhead.len );
} }
if( len < mhead.len ) if( len < mhead.len )
...@@ -336,7 +378,7 @@ mbErrCode ModbusTCPSession::pre_send_request( ModbusMessage& request ) ...@@ -336,7 +378,7 @@ mbErrCode ModbusTCPSession::pre_send_request( ModbusMessage& request )
dlog->info(false) << endl; dlog->info(false) << endl;
} }
sendData((unsigned char*)(&curQueryHeader),sizeof(curQueryHeader)); sendData((unsigned char*)(&curQueryHeader), sizeof(curQueryHeader));
curQueryHeader.swapdata(); curQueryHeader.swapdata();
return erNoError; return erNoError;
...@@ -356,15 +398,17 @@ void ModbusTCPSession::cleanInputStream() ...@@ -356,15 +398,17 @@ void ModbusTCPSession::cleanInputStream()
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPSession::terminate() void ModbusTCPSession::terminate()
{ {
ModbusServer::terminate();
if( dlog->is_info() ) if( dlog->is_info() )
dlog->info() << peername << "(terminate)..." << endl; dlog->info() << peername << "(terminate)..." << endl;
cancelled = true; cancelled = true;
io.stop(); io.stop();
idle.stop(); ioTimeout.stop();
close(sfd);
ModbusServer::terminate();
sock.reset(); // close..
final();
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readCoilStatus( ReadCoilMessage& query, mbErrCode ModbusTCPSession::readCoilStatus( ReadCoilMessage& query,
...@@ -505,8 +549,7 @@ ModbusRTU::mbErrCode ModbusTCPSession::fileTransfer( ModbusRTU::FileTransferMess ...@@ -505,8 +549,7 @@ ModbusRTU::mbErrCode ModbusTCPSession::fileTransfer( ModbusRTU::FileTransferMess
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPSession::setChannelTimeout( timeout_t msec ) void ModbusTCPSession::setChannelTimeout( timeout_t msec )
{ {
// setTimeout(msec); setSessionTimeout(msec);
#warning NOT YET!!
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPSession::connectFinalSession( FinalSlot sl ) void ModbusTCPSession::connectFinalSession( FinalSlot sl )
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# This file is part of the UniSet library # # This file is part of the UniSet library #
############################################################################ ############################################################################
noinst_LTLIBRARIES = libTCP.la noinst_LTLIBRARIES = libTCP.la
libTCP_la_SOURCES = UTCPStream.cc TCPCheck.cc libTCP_la_SOURCES = UTCPCore.cc UTCPStream.cc USocket.cc UTCPSocket.cc TCPCheck.cc
libTCP_la_CXXFLAGS = $(SIGC_CFLAGS) $(COMCPP_CFLAGS) libTCP_la_CXXFLAGS = $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
libTCP_la_LIBADD = $(SIGC_LIBS) $(COMCPP_LIBS) libTCP_la_LIBADD = $(SIGC_LIBS) $(COMCPP_LIBS)
......
#include "USocket.h"
#include "UTCPCore.h"
// -------------------------------------------------------------------------
using namespace std;
// -------------------------------------------------------------------------
USocket::~USocket()
{
endSocket();
}
// -------------------------------------------------------------------------
USocket::USocket( int sock ):
Socket(accept(sock, NULL, NULL))
{
init();
}
// -------------------------------------------------------------------------
bool USocket::setKeepAliveParams( timeout_t timeout_sec, int keepcnt, int keepintvl )
{
return UTCPCore::setKeepAliveParams(so, timeout_sec, keepcnt, keepintvl);
}
// -------------------------------------------------------------------------
int USocket::getSocket()
{
return so;
}
// -------------------------------------------------------------------------
void USocket::init( bool throwflag )
{
setError(throwflag);
setKeepAlive(true);
setLinger(true);
setKeepAliveParams();
}
// -------------------------------------------------------------------------
#include "UTCPCore.h"
// glibc..
#include <netinet/tcp.h>
// -------------------------------------------------------------------------
using namespace std;
// -------------------------------------------------------------------------
bool UTCPCore::setKeepAliveParams( int fd, timeout_t timeout_sec, int keepcnt, int keepintvl )
{
int enable = 1;
bool ok = true;
if( setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&enable, sizeof(enable)) == -1 )
ok = false;
if( setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void*) &keepcnt, sizeof(keepcnt)) == -1 )
ok = false;
if( setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void*) &keepintvl, sizeof (keepintvl)) == -1 )
ok = false;
if( setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void*) &timeout_sec, sizeof (timeout_sec)) == -1 )
ok = false;
return ok;
}
// -------------------------------------------------------------------------
#include <iostream>
#include <string>
#include <fcntl.h>
#include <errno.h>
#include <cstring>
#include <cc++/socket.h>
#include "UTCPSocket.h"
#include "PassiveTimer.h"
#include "UniSetTypes.h"
#include "UTCPCore.h"
// -------------------------------------------------------------------------
using namespace std;
// -------------------------------------------------------------------------
UTCPSocket::~UTCPSocket()
{
endSocket();
// shutdown(so, SHUT_RDWR);
}
// -------------------------------------------------------------------------
UTCPSocket::UTCPSocket( int sock ):
TCPSocket(NULL)
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
so = accept(sock, (struct sockaddr*)&client_addr, &client_len);
if( so < 0 )
{
endSocket();
error(errConnectRejected);
return;
}
Socket::state = CONNECTED;
}
// -------------------------------------------------------------------------
UTCPSocket::UTCPSocket( const std::string& hname, unsigned backlog, unsigned mss ):
TCPSocket(hname.c_str(), backlog, mss)
{
init();
}
// -------------------------------------------------------------------------
UTCPSocket::UTCPSocket(const ost::IPV4Address& bind, ost::tpport_t port, unsigned backlog, unsigned mss):
TCPSocket(bind, port, backlog, mss)
{
init();
}
// -------------------------------------------------------------------------
bool UTCPSocket::setKeepAliveParams(timeout_t timeout_sec, int keepcnt, int keepintvl )
{
return UTCPCore::setKeepAliveParams(so, timeout_sec, keepcnt, keepintvl);
}
// -------------------------------------------------------------------------
bool UTCPSocket::setNoDelay(bool enable)
{
return ( TCPSocket::setNoDelay(enable) == 0 );
}
// -------------------------------------------------------------------------
int UTCPSocket::getSocket()
{
return so;
}
// -------------------------------------------------------------------------
void UTCPSocket::init( bool throwflag )
{
setError(throwflag);
setKeepAlive(true);
setLinger(true);
setKeepAliveParams();
}
// -------------------------------------------------------------------------
ssize_t UTCPSocket::writeData(const void* buf, size_t len, timeout_t t)
{
return TCPSocket::writeData(buf, len, t);
}
// -------------------------------------------------------------------------
ssize_t UTCPSocket::readData(void* buf, size_t len, char separator, timeout_t t)
{
return TCPSocket::readData(buf, len, separator, t);
}
// -------------------------------------------------------------------------
...@@ -23,9 +23,7 @@ ...@@ -23,9 +23,7 @@
#include "UTCPStream.h" #include "UTCPStream.h"
#include "PassiveTimer.h" #include "PassiveTimer.h"
#include "UniSetTypes.h" #include "UniSetTypes.h"
#include "UTCPCore.h"
// glibc..
#include <netinet/tcp.h>
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
using namespace std; using namespace std;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -41,23 +39,7 @@ UTCPStream::UTCPStream(): ...@@ -41,23 +39,7 @@ UTCPStream::UTCPStream():
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
bool UTCPStream::setKeepAliveParams(timeout_t timeout_sec, int keepcnt, int keepintvl ) bool UTCPStream::setKeepAliveParams(timeout_t timeout_sec, int keepcnt, int keepintvl )
{ {
SOCKET fd = TCPStream::so; return UTCPCore::setKeepAliveParams(so, timeout_sec, keepcnt, keepintvl);
int enable = 1;
bool ok = true;
if( setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&enable, sizeof(enable)) == -1 )
ok = false;
if( setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void*) &keepcnt, sizeof(keepcnt)) == -1 )
ok = false;
if( setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void*) &keepintvl, sizeof (keepintvl)) == -1 )
ok = false;
if( setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void*) &timeout_sec, sizeof (timeout_sec)) == -1 )
ok = false;
return ok;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
bool UTCPStream::isSetLinger() bool UTCPStream::isSetLinger()
...@@ -80,12 +62,12 @@ bool UTCPStream::setNoDelay(bool enable) ...@@ -80,12 +62,12 @@ bool UTCPStream::setNoDelay(bool enable)
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ssize_t UTCPStream::writeData(const void* buf, size_t len, timeout_t t) ssize_t UTCPStream::writeData(const void* buf, size_t len, timeout_t t)
{ {
return TCPStream::writeData(buf,len,t); return TCPStream::writeData(buf, len, t);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ssize_t UTCPStream::readData(void* buf, size_t len, char separator, timeout_t t) ssize_t UTCPStream::readData(void* buf, size_t len, char separator, timeout_t t)
{ {
return TCPStream::readData(buf,len,separator,t); return TCPStream::readData(buf, len, separator, t);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
int UTCPStream::getSocket() int UTCPStream::getSocket()
......
...@@ -34,6 +34,7 @@ bool DBNetInterface::connect( const std::string& param ) ...@@ -34,6 +34,7 @@ bool DBNetInterface::connect( const std::string& param )
dbname = param.substr(prev, pos - prev); dbname = param.substr(prev, pos - prev);
break; break;
} }
return nconnect( host, user, pswd, dbname ); return nconnect( host, user, pswd, dbname );
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
......
...@@ -146,9 +146,6 @@ extensions/ModbusSlave/Makefile.am ...@@ -146,9 +146,6 @@ extensions/ModbusSlave/Makefile.am
extensions/ModbusSlave/MBSlave.cc extensions/ModbusSlave/MBSlave.cc
extensions/ModbusSlave/mbslave.cc extensions/ModbusSlave/mbslave.cc
extensions/ModbusSlave/MBSlave.h extensions/ModbusSlave/MBSlave.h
extensions/ModbusSlave/mbtcp-persistentslave.cc
extensions/ModbusSlave/MBTCPPersistentSlave.cc
extensions/ModbusSlave/MBTCPPersistentSlave.h
extensions/ModbusSlave/test.xml extensions/ModbusSlave/test.xml
extensions/RRDServer/libUniSet2RRDServer.pc.in extensions/RRDServer/libUniSet2RRDServer.pc.in
extensions/RRDServer/main.cc extensions/RRDServer/main.cc
...@@ -311,7 +308,10 @@ include/UniSetManager.h ...@@ -311,7 +308,10 @@ include/UniSetManager.h
include/UniSetObject.h include/UniSetObject.h
include/UniSetTypes.h include/UniSetTypes.h
include/UniXML.h include/UniXML.h
include/UTCPCore.h
include/UTCPStream.h include/UTCPStream.h
include/UTCPSocket.h
include/USocket.h
include/WDTInterface.h include/WDTInterface.h
lib/Makefile.am lib/Makefile.am
python/examples/test.xml python/examples/test.xml
...@@ -349,7 +349,10 @@ src/Communications/Modbus/ModbusTCPTypes.cc ...@@ -349,7 +349,10 @@ src/Communications/Modbus/ModbusTCPTypes.cc
src/Communications/Modbus/ModbusTypes.cc src/Communications/Modbus/ModbusTypes.cc
src/Communications/TCP/Makefile.am src/Communications/TCP/Makefile.am
src/Communications/TCP/TCPCheck.cc src/Communications/TCP/TCPCheck.cc
src/Communications/TCP/UTCPCore.cc
src/Communications/TCP/UTCPStream.cc src/Communications/TCP/UTCPStream.cc
src/Communications/TCP/UTCPSocket.cc
src/Communications/TCP/USocket.cc
src/Communications/ComPort.cc src/Communications/ComPort.cc
src/Communications/ComPort485F.cc src/Communications/ComPort485F.cc
src/Communications/Makefile.am src/Communications/Makefile.am
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment