Commit 12ee9dc5 authored by Pavel Vainerman's avatar Pavel Vainerman Committed by Pavel Vainerman

[modbus slave]: supported socket reopen timeout

parent a8ff6725
...@@ -248,6 +248,13 @@ namespace uniset ...@@ -248,6 +248,13 @@ namespace uniset
vmonit(sessTimeout); vmonit(sessTimeout);
tmpval = conf->getArgInt("--" + prefix + "-socket-timeout", it.getProp("socketTimeout"));
if( tmpval > 0 )
sockTimeout = tmpval;
vmonit(sockTimeout);
tmpval = conf->getArgInt("--" + prefix + "-session-maxnum", it.getProp("sessMaxNum")); tmpval = conf->getArgInt("--" + prefix + "-session-maxnum", it.getProp("sessMaxNum"));
if( tmpval > 0 ) if( tmpval > 0 )
...@@ -642,6 +649,8 @@ namespace uniset ...@@ -642,6 +649,8 @@ namespace uniset
i.second.ptTimeout.reset(); i.second.ptTimeout.reset();
tcpserver->setMaxSessions( sessMaxNum ); tcpserver->setMaxSessions( sessMaxNum );
tcpserver->setSessionTimeout(sessTimeout);
tcpserver->setSocketTimeout(sockTimeout);
if( vaddr.empty() ) if( vaddr.empty() )
{ {
......
...@@ -596,6 +596,7 @@ namespace uniset ...@@ -596,6 +596,7 @@ namespace uniset
// TCPServer section.. // TCPServer section..
void initTCPClients( UniXML::iterator confnode ); void initTCPClients( UniXML::iterator confnode );
timeout_t sockTimeout = { UniSetTimer::WaitUpTime }; /*!< таймаут на переоткрытие сокета (если нет сессий) */
timeout_t sessTimeout = { 2000 }; /*!< таймаут на сессию */ timeout_t sessTimeout = { 2000 }; /*!< таймаут на сессию */
timeout_t updateStatTime = { 4000 }; timeout_t updateStatTime = { 4000 };
ModbusTCPServer::Sessions sess; /*!< список открытых сессий */ ModbusTCPServer::Sessions sess; /*!< список открытых сессий */
......
...@@ -92,6 +92,12 @@ namespace uniset ...@@ -92,6 +92,12 @@ namespace uniset
void setTimer( timeout_t msec ); void setTimer( timeout_t msec );
timeout_t getTimer() const noexcept; timeout_t getTimer() const noexcept;
// Таймаут для переоткрытия сокета.
// Если в течение msec миллисекунд нет действующих соединений
// сокет переоткрывается
void setSocketTimeout( timeout_t msec );
timeout_t getSocketTimeout() const noexcept;
protected: protected:
// ожидание (при этом время отдаётся eventloop-у) // ожидание (при этом время отдаётся eventloop-у)
...@@ -105,6 +111,8 @@ namespace uniset ...@@ -105,6 +111,8 @@ namespace uniset
virtual void ioAccept(ev::io& watcher, int revents); virtual void ioAccept(ev::io& watcher, int revents);
void onTimer( ev::timer& t, int revents ); void onTimer( ev::timer& t, int revents );
void onSocketTimeout( ev::timer& t, int revents );
void onSocketResetTimeout( ev::async& watcher, int revents ) noexcept;
void sessionFinished( const ModbusTCPSession* s ); void sessionFinished( const ModbusTCPSession* s );
...@@ -145,6 +153,11 @@ namespace uniset ...@@ -145,6 +153,11 @@ namespace uniset
ev::timer ioTimer; ev::timer ioTimer;
std::shared_ptr<UTCPSocket> sock; std::shared_ptr<UTCPSocket> sock;
ev::timer sockTimeout;
timeout_t socketTimeout_msec = { UniSetTimer::WaitUpTime };
double tmSockTimeout = { 0.0 };
ev::async asyncResetSockTimeout;
std::unordered_set<ModbusRTU::ModbusAddr> vmbaddr; std::unordered_set<ModbusRTU::ModbusAddr> vmbaddr;
TimerSignal m_timer_signal; TimerSignal m_timer_signal;
...@@ -154,6 +167,8 @@ namespace uniset ...@@ -154,6 +167,8 @@ namespace uniset
PassiveTimer ptWait; PassiveTimer ptWait;
private: private:
void createSocket();
// транслирование сигналов от Sessions.. // транслирование сигналов от Sessions..
void postReceiveEvent( ModbusRTU::mbErrCode res ); void postReceiveEvent( ModbusRTU::mbErrCode res );
ModbusRTU::mbErrCode preReceiveEvent( const std::unordered_set<ModbusRTU::ModbusAddr> vaddr, timeout_t tout ); ModbusRTU::mbErrCode preReceiveEvent( const std::unordered_set<ModbusRTU::ModbusAddr> vaddr, timeout_t tout );
......
...@@ -46,6 +46,8 @@ namespace uniset ...@@ -46,6 +46,8 @@ namespace uniset
io.set<ModbusTCPServer, &ModbusTCPServer::ioAccept>(this); io.set<ModbusTCPServer, &ModbusTCPServer::ioAccept>(this);
ioTimer.set<ModbusTCPServer, &ModbusTCPServer::onTimer>(this); ioTimer.set<ModbusTCPServer, &ModbusTCPServer::onTimer>(this);
sockTimeout.set<ModbusTCPServer, &ModbusTCPServer::onSocketTimeout>(this);
asyncResetSockTimeout.set<ModbusTCPServer, &ModbusTCPServer::onSocketResetTimeout>(this);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -108,36 +110,50 @@ namespace uniset ...@@ -108,36 +110,50 @@ namespace uniset
return evIsActive() && sock; return evIsActive() && sock;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPServer::evprepare() void ModbusTCPServer::createSocket()
{ {
try try
{ {
sock = make_shared<UTCPSocket>(iaddr, port); auto tmpSock = make_shared<UTCPSocket>(iaddr, port);
if( sock )
sock.reset();
sock = tmpSock;
} }
catch( const Poco::Net::NetException& ex ) catch( const Poco::Net::NetException& ex )
{ {
ostringstream err; ostringstream err;
err << "(ModbusTCPServer::evprepare): connect " << iaddr << ":" << port << " err: " << ex.what(); err << "(ModbusTCPServer::createSocket): connect " << iaddr << ":" << port << " err: " << ex.what();
dlog->crit() << err.str() << endl; dlog->crit() << err.str() << endl;
throw uniset::SystemError(err.str()); throw uniset::SystemError(err.str());
} }
catch( const std::exception& ex ) catch( const std::exception& ex )
{ {
ostringstream err; ostringstream err;
err << "(ModbusTCPServer::evprepare): connect " << iaddr << ":" << port << " err: " << ex.what(); err << "(ModbusTCPServer::createSocket): connect " << iaddr << ":" << port << " err: " << ex.what();
dlog->crit() << err.str() << endl; dlog->crit() << err.str() << endl;
throw uniset::SystemError(err.str()); throw uniset::SystemError(err.str());
} }
sock->setBlocking(false); sock->setBlocking(false);
}
// -------------------------------------------------------------------------
void ModbusTCPServer::evprepare()
{
createSocket();
io.set(loop); io.set(loop);
io.start(sock->getSocket(), ev::READ); io.start(sock->getSocket(), ev::READ);
ioTimer.set(loop); asyncResetSockTimeout.set(loop);
asyncResetSockTimeout.start();
ioTimer.set(loop);
if( tmTime_msec != UniSetTimer::WaitUpTime ) if( tmTime_msec != UniSetTimer::WaitUpTime )
ioTimer.start(0, tmTime); ioTimer.start(0, tmTime);
sockTimeout.set(loop);
if( socketTimeout_msec > 0 && socketTimeout_msec != UniSetTimer::WaitUpTime )
sockTimeout.start(0, tmSockTimeout);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPServer::terminate() void ModbusTCPServer::terminate()
...@@ -155,6 +171,8 @@ namespace uniset ...@@ -155,6 +171,8 @@ namespace uniset
ioTimer.stop(); ioTimer.stop();
io.stop(); io.stop();
sockTimeout.stop();
asyncResetSockTimeout.stop();
auto lst(slist); auto lst(slist);
...@@ -183,6 +201,7 @@ namespace uniset ...@@ -183,6 +201,7 @@ namespace uniset
{ {
slist.erase(i); slist.erase(i);
sessCount--; sessCount--;
asyncResetSockTimeout.send();
return; return;
} }
} }
...@@ -238,7 +257,29 @@ namespace uniset ...@@ -238,7 +257,29 @@ namespace uniset
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
timeout_t ModbusTCPServer::getTimer() const noexcept timeout_t ModbusTCPServer::getTimer() const noexcept
{ {
return tmTime; return tmTime_msec;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setSocketTimeout( timeout_t msec )
{
socketTimeout_msec = msec;
if( msec == UniSetTimer::WaitUpTime || msec == 0 )
{
socketTimeout_msec = 0;
if( sockTimeout.is_active() )
sockTimeout.stop();
}
else
{
tmSockTimeout = (double)msec / 1000.;
if( sockTimeout.is_active() )
sockTimeout.start( 0, tmSockTimeout );
}
}
// ------------------------------------------------------------------------
timeout_t ModbusTCPServer::getSocketTimeout() const noexcept
{
return socketTimeout_msec;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPServer::iowait( timeout_t msec ) void ModbusTCPServer::iowait( timeout_t msec )
...@@ -286,6 +327,9 @@ namespace uniset ...@@ -286,6 +327,9 @@ namespace uniset
connCount++; connCount++;
if( sockTimeout.is_active() )
sockTimeout.again();
auto s = make_shared<ModbusTCPSession>(ss, vmbaddr, sessTimeout); auto s = make_shared<ModbusTCPSession>(ss, vmbaddr, sessTimeout);
s->connectReadCoil( sigc::mem_fun(this, &ModbusTCPServer::readCoilStatus) ); s->connectReadCoil( sigc::mem_fun(this, &ModbusTCPServer::readCoilStatus) );
s->connectReadInputStatus( sigc::mem_fun(this, &ModbusTCPServer::readInputStatus) ); s->connectReadInputStatus( sigc::mem_fun(this, &ModbusTCPServer::readInputStatus) );
...@@ -331,26 +375,83 @@ namespace uniset ...@@ -331,26 +375,83 @@ namespace uniset
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPServer::onTimer( ev::timer& t, int revents ) void ModbusTCPServer::onTimer( ev::timer& t, int revents )
{ {
if (EV_ERROR & revents) if (EV_ERROR & revents)
{ {
if( dlog->is_crit() ) if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioTimer): invalid event" << endl; dlog->crit() << myname << "(ModbusTCPServer::ioTimer): invalid event" << endl;
return;
}
try
{
m_timer_signal.emit();
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(onTimer): " << ex.what() << endl;
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::onSocketResetTimeout( ev::async& watcher, int revents ) noexcept
{
if( EV_ERROR & revents )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketResetTimeout): invalid event" << endl;
return; return;
} }
try if( dlog->is_info() )
{ dlog->info() << myname << "(ModbusTCPServer::onSocketResetTimeout): reset socket timeout.." << endl;
m_timer_signal.emit();
} if( sockTimeout.is_active() )
catch( std::exception& ex ) sockTimeout.again();
{ }
if( dlog->is_crit() ) // -------------------------------------------------------------------------
dlog->crit() << myname << "(onTimer): " << ex.what() << endl; void ModbusTCPServer::onSocketTimeout( ev::timer& t, int revents )
} {
if (EV_ERROR & revents)
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketTimeout): invalid event" << endl;
return;
}
{
std::lock_guard<std::mutex> l(sMutex);
if( !slist.empty())
{
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer::onSocketTimeout): check socket [OK].." << endl;
t.again();
return;
}
}
if( dlog->is_warn() )
dlog->warn() << myname << "(ModbusTCPServer::onSocketTimeout): no connections.. recreate socket.." << endl;
try
{
createSocket();
if( io.is_active() )
io.stop();
io.start(sock->getSocket(), ev::READ);
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketTimeout): recreate socket ERROR: " << ex.what() << endl;
}
t.again();
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
mbErrCode ModbusTCPServer::realReceive( const std::unordered_set<ModbusAddr>& vaddr, timeout_t msecTimeout ) mbErrCode ModbusTCPServer::realReceive( const std::unordered_set<ModbusAddr>& vaddr, timeout_t msecTimeout )
{ {
return ModbusRTU::erOperationFailed; return ModbusRTU::erOperationFailed;
......
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