Reconnect sicherer gestaltet

Abfrage von .reconnecting eingebaut
Dirtybytes und Timeout lösen keine Exception mehr aus sondern einen Reconnect
This commit is contained in:
2019-08-16 22:32:27 +02:00
parent da8f944486
commit 2009ed9ce5
4 changed files with 168 additions and 45 deletions

View File

@@ -18,6 +18,9 @@ Global Attributes</h3>
Classes</h3> Classes</h3>
<table> <table>
<tr> <tr>
<td><a style="color:#0000FF" href="#AclException">AclException</a></td>
<td>Probleme mit Berechtigungen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#NetFH">NetFH</a></td> <td><a style="color:#0000FF" href="#NetFH">NetFH</a></td>
<td>Netzwerk File Handler fuer das Prozessabbild.</td> <td>Netzwerk File Handler fuer das Prozessabbild.</td>
</tr><tr> </tr><tr>
@@ -37,6 +40,37 @@ Functions</h3>
<tr><td>None</td></tr> <tr><td>None</td></tr>
</table> </table>
<hr /><hr /> <hr /><hr />
<a NAME="AclException" ID="AclException"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">AclException</h2>
<p>
Probleme mit Berechtigungen.
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
Exception
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="NetFH" ID="NetFH"></a> <a NAME="NetFH" ID="NetFH"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">NetFH</h2> <h2 style="background-color:#FFFFFF;color:#0000FF">NetFH</h2>
<p> <p>
@@ -54,7 +88,7 @@ Thread
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3> Class Attributes</h3>
<table> <table>
<tr><td>__slots__</td></tr><tr><td>closed</td></tr><tr><td>name</td></tr><tr><td>timeout</td></tr> <tr><td>__slots__</td></tr><tr><td>closed</td></tr><tr><td>name</td></tr><tr><td>reconnecting</td></tr><tr><td>timeout</td></tr>
</table> </table>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3> Class Methods</h3>
@@ -98,6 +132,9 @@ Methods</h3>
<td><a style="color:#0000FF" href="#NetFH.get_name">get_name</a></td> <td><a style="color:#0000FF" href="#NetFH.get_name">get_name</a></td>
<td>Verbindugnsnamen zurueckgeben.</td> <td>Verbindugnsnamen zurueckgeben.</td>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#NetFH.get_reconnecting">get_reconnecting</a></td>
<td>Interner reconnect aktiv wegen Netzwerkfehlern.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#NetFH.get_timeout">get_timeout</a></td> <td><a style="color:#0000FF" href="#NetFH.get_timeout">get_timeout</a></td>
<td>Gibt aktuellen Timeout zurueck.</td> <td>Gibt aktuellen Timeout zurueck.</td>
</tr><tr> </tr><tr>
@@ -241,6 +278,17 @@ Verbindugnsnamen zurueckgeben.
<dd> <dd>
<class 'str'> IP:PORT <class 'str'> IP:PORT
</dd> </dd>
</dl><a NAME="NetFH.get_reconnecting" ID="NetFH.get_reconnecting"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
NetFH.get_reconnecting</h3>
<b>get_reconnecting</b>(<i></i>)
<p>
Interner reconnect aktiv wegen Netzwerkfehlern.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn reconnect aktiv
</dd>
</dl><a NAME="NetFH.get_timeout" ID="NetFH.get_timeout"></a> </dl><a NAME="NetFH.get_timeout" ID="NetFH.get_timeout"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
NetFH.get_timeout</h3> NetFH.get_timeout</h3>
@@ -385,7 +433,7 @@ _RevPiModIO
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3> Class Attributes</h3>
<table> <table>
<tr><td>__slots__</td></tr> <tr><td>__slots__</td></tr><tr><td>reconnecting</td></tr>
</table> </table>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3> Class Methods</h3>
@@ -408,6 +456,9 @@ Methods</h3>
<td><a style="color:#0000FF" href="#RevPiNetIO.get_jconfigrsc">get_jconfigrsc</a></td> <td><a style="color:#0000FF" href="#RevPiNetIO.get_jconfigrsc">get_jconfigrsc</a></td>
<td>Laedt die piCotry Konfiguration und erstellt ein <class 'dict'>.</td> <td>Laedt die piCotry Konfiguration und erstellt ein <class 'dict'>.</td>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#RevPiNetIO.get_reconnecting">get_reconnecting</a></td>
<td>Interner reconnect aktiv wegen Netzwerkfehlern.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiNetIO.net_cleardefaultvalues">net_cleardefaultvalues</a></td> <td><a style="color:#0000FF" href="#RevPiNetIO.net_cleardefaultvalues">net_cleardefaultvalues</a></td>
<td>Loescht Defaultwerte vom PLC Slave.</td> <td>Loescht Defaultwerte vom PLC Slave.</td>
</tr><tr> </tr><tr>
@@ -476,6 +527,17 @@ Laedt die piCotry Konfiguration und erstellt ein <class 'dict'>.
<dd> <dd>
<class 'dict'> der piCtory Konfiguration <class 'dict'> der piCtory Konfiguration
</dd> </dd>
</dl><a NAME="RevPiNetIO.get_reconnecting" ID="RevPiNetIO.get_reconnecting"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiNetIO.get_reconnecting</h3>
<b>get_reconnecting</b>(<i></i>)
<p>
Interner reconnect aktiv wegen Netzwerkfehlern.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn reconnect aktiv
</dd>
</dl><a NAME="RevPiNetIO.net_cleardefaultvalues" ID="RevPiNetIO.net_cleardefaultvalues"></a> </dl><a NAME="RevPiNetIO.net_cleardefaultvalues" ID="RevPiNetIO.net_cleardefaultvalues"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiNetIO.net_cleardefaultvalues</h3> RevPiNetIO.net_cleardefaultvalues</h3>

View File

@@ -192,11 +192,13 @@ revpimodio2.netio.NetFH.closed?7
revpimodio2.netio.NetFH.flush?4() revpimodio2.netio.NetFH.flush?4()
revpimodio2.netio.NetFH.get_closed?4() revpimodio2.netio.NetFH.get_closed?4()
revpimodio2.netio.NetFH.get_name?4() revpimodio2.netio.NetFH.get_name?4()
revpimodio2.netio.NetFH.get_reconnecting?4()
revpimodio2.netio.NetFH.get_timeout?4() revpimodio2.netio.NetFH.get_timeout?4()
revpimodio2.netio.NetFH.ioctl?4(request, arg=b'') revpimodio2.netio.NetFH.ioctl?4(request, arg=b'')
revpimodio2.netio.NetFH.name?7 revpimodio2.netio.NetFH.name?7
revpimodio2.netio.NetFH.read?4(length) revpimodio2.netio.NetFH.read?4(length)
revpimodio2.netio.NetFH.readpictory?4() revpimodio2.netio.NetFH.readpictory?4()
revpimodio2.netio.NetFH.reconnecting?7
revpimodio2.netio.NetFH.run?4() revpimodio2.netio.NetFH.run?4()
revpimodio2.netio.NetFH.seek?4(position) revpimodio2.netio.NetFH.seek?4(position)
revpimodio2.netio.NetFH.set_dirtybytes?4(position, dirtybytes) revpimodio2.netio.NetFH.set_dirtybytes?4(position, dirtybytes)
@@ -208,8 +210,10 @@ revpimodio2.netio.NetFH?1(address, timeout=500)
revpimodio2.netio.RevPiNetIO._create_myfh?5() revpimodio2.netio.RevPiNetIO._create_myfh?5()
revpimodio2.netio.RevPiNetIO.disconnect?4() revpimodio2.netio.RevPiNetIO.disconnect?4()
revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4() revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4()
revpimodio2.netio.RevPiNetIO.get_reconnecting?4()
revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None) revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None)
revpimodio2.netio.RevPiNetIO.net_setdefaultvalues?4(device=None) revpimodio2.netio.RevPiNetIO.net_setdefaultvalues?4(device=None)
revpimodio2.netio.RevPiNetIO.reconnecting?7
revpimodio2.netio.RevPiNetIO?1(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False) revpimodio2.netio.RevPiNetIO?1(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False)
revpimodio2.netio.RevPiNetIODriver?1(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None, direct_output=False) revpimodio2.netio.RevPiNetIODriver?1(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None, direct_output=False)
revpimodio2.netio.RevPiNetIOSelected?1(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False) revpimodio2.netio.RevPiNetIOSelected?1(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False)

View File

@@ -1,3 +1,4 @@
AclException Exception
Base Device Base Device
Connect Core Connect Core
Core Base Core Base

View File

@@ -25,6 +25,13 @@ _syspictory = b'\x01PI\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17'
_sysflush = b'\x01SD\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x17' _sysflush = b'\x01SD\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x17'
class AclException(Exception):
"""Probleme mit Berechtigungen."""
pass
class NetFH(Thread): class NetFH(Thread):
"""Netzwerk File Handler fuer das Prozessabbild. """Netzwerk File Handler fuer das Prozessabbild.
@@ -54,7 +61,7 @@ class NetFH(Thread):
self.__flusherr = False self.__flusherr = False
self.__sockact = False self.__sockact = False
self.__sockerr = Event() self.__sockerr = Event()
self.__sockend = False self.__sockend = Event()
self.__socklock = Lock() self.__socklock = Lock()
self.__timeout = None self.__timeout = None
self.__trigger = False self.__trigger = False
@@ -90,10 +97,10 @@ class NetFH(Thread):
if bytecode == b'\x18': if bytecode == b'\x18':
# Alles beenden, wenn nicht erlaubt # Alles beenden, wenn nicht erlaubt
self.__sockend = True self.__sockend.set()
self.__sockerr.set() self.__sockerr.set()
self._slavesock.close() self._slavesock.close()
raise RuntimeError( raise AclException(
"write access to the process image is not permitted - use " "write access to the process image is not permitted - use "
"monitoring=True or check aclplcslave.conf on RevPi and " "monitoring=True or check aclplcslave.conf on RevPi and "
"reload revpipyload!" "reload revpipyload!"
@@ -151,11 +158,12 @@ class NetFH(Thread):
@returns Empfangende Bytes @returns Empfangende Bytes
""" """
if self.__sockend: if self.__sockend.is_set():
raise ValueError("I/O operation on closed file") raise ValueError("I/O operation on closed file")
with self.__socklock: with self.__socklock:
self._slavesock.sendall(send_bytes) self._slavesock.sendall(send_bytes)
# FIXME: Schleife bis Daten empfangen sind einbauen
recv = self._slavesock.recv(recv_count) recv = self._slavesock.recv(recv_count)
self.__trigger = True self.__trigger = True
return recv return recv
@@ -163,10 +171,13 @@ class NetFH(Thread):
def clear_dirtybytes(self, position=None): def clear_dirtybytes(self, position=None):
"""Entfernt die konfigurierten Dirtybytes vom RevPi Slave. """Entfernt die konfigurierten Dirtybytes vom RevPi Slave.
@param position Startposition der Dirtybytes""" @param position Startposition der Dirtybytes"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("I/O operation on closed file") raise ValueError("I/O operation on closed file")
with self.__socklock: error = False
try:
self.__socklock.acquire()
if position is None: if position is None:
# Alle Dirtybytes löschen # Alle Dirtybytes löschen
self._slavesock.sendall(_sysdeldirty) self._slavesock.sendall(_sysdeldirty)
@@ -184,40 +195,52 @@ class NetFH(Thread):
# ACL prüfen und ggf Fehler werfen # ACL prüfen und ggf Fehler werfen
self.__check_acl(check) self.__check_acl(check)
self.__sockerr.set()
raise IOError("clear dirtybytes error on network") raise IOError("clear dirtybytes error on network")
except AclException:
raise
except Exception:
error = True
finally:
self.__socklock.release()
# Daten bei Erfolg übernehmen # Daten immer übernehmen
if position is None: if position is None:
self.__dictdirty = {} self.__dictdirty = {}
elif position in self.__dictdirty: elif position in self.__dictdirty:
del self.__dictdirty[position] del self.__dictdirty[position]
if error:
# Fehler nach übernahme der Daten auslösen um diese zu setzen
self.__sockerr.set()
self.__trigger = True self.__trigger = True
def close(self): def close(self):
"""Verbindung trennen.""" """Verbindung trennen."""
if self.__sockend: if self.__sockend.is_set():
return return
self.__sockend = True self.__sockend.set()
self.__sockerr.set() self.__sockerr.set()
# Vom Socket sauber trennen # Vom Socket sauber trennen
if self._slavesock is not None: if self._slavesock is not None:
with self.__socklock:
try: try:
if self.__sockend: self.__socklock.acquire()
self._slavesock.send(_sysexit) self._slavesock.send(_sysexit)
else:
# NOTE: Wird das benötigt?
self._slavesock.shutdown(socket.SHUT_RDWR) self._slavesock.shutdown(socket.SHUT_RDWR)
except Exception: except Exception:
pass pass
finally:
self.__socklock.release()
self._slavesock.close() self._slavesock.close()
def flush(self): def flush(self):
"""Schreibpuffer senden.""" """Schreibpuffer senden."""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("flush of closed file") raise ValueError("flush of closed file")
with self.__socklock: with self.__socklock:
@@ -248,13 +271,18 @@ class NetFH(Thread):
def get_closed(self): def get_closed(self):
"""Pruefen ob Verbindung geschlossen ist. """Pruefen ob Verbindung geschlossen ist.
@return True, wenn Verbindung geschlossen ist""" @return True, wenn Verbindung geschlossen ist"""
return self.__sockend return self.__sockend.is_set()
def get_name(self): def get_name(self):
"""Verbindugnsnamen zurueckgeben. """Verbindugnsnamen zurueckgeben.
@return <class 'str'> IP:PORT""" @return <class 'str'> IP:PORT"""
return "{0}:{1}".format(*self._address) return "{0}:{1}".format(*self._address)
def get_reconnecting(self):
"""Interner reconnect aktiv wegen Netzwerkfehlern.
@return True, wenn reconnect aktiv"""
return self.__sockerr.is_set()
def get_timeout(self): def get_timeout(self):
"""Gibt aktuellen Timeout zurueck. """Gibt aktuellen Timeout zurueck.
@return <class 'int'> in Millisekunden""" @return <class 'int'> in Millisekunden"""
@@ -264,7 +292,7 @@ class NetFH(Thread):
"""IOCTL Befehle ueber das Netzwerk senden. """IOCTL Befehle ueber das Netzwerk senden.
@param request Request as <class 'int'> @param request Request as <class 'int'>
@param arg Argument as <class 'byte'>""" @param arg Argument as <class 'byte'>"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("read of closed file") raise ValueError("read of closed file")
if not (isinstance(arg, bytes) and len(arg) <= 1024): if not (isinstance(arg, bytes) and len(arg) <= 1024):
@@ -295,7 +323,7 @@ class NetFH(Thread):
"""Daten ueber das Netzwerk lesen. """Daten ueber das Netzwerk lesen.
@param length Anzahl der Bytes @param length Anzahl der Bytes
@return Gelesene <class 'bytes'>""" @return Gelesene <class 'bytes'>"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("read of closed file") raise ValueError("read of closed file")
with self.__socklock: with self.__socklock:
@@ -307,8 +335,8 @@ class NetFH(Thread):
) )
bytesbuff = bytearray() bytesbuff = bytearray()
while not self.__sockend and len(bytesbuff) < length: while not self.__sockend.is_set() and len(bytesbuff) < length:
rbytes = self._slavesock.recv(1024) rbytes = self._slavesock.recv(256)
if rbytes == b'': if rbytes == b'':
self.__sockerr.set() self.__sockerr.set()
@@ -323,33 +351,36 @@ class NetFH(Thread):
def readpictory(self): def readpictory(self):
"""Ruft die piCtory Konfiguration ab. """Ruft die piCtory Konfiguration ab.
@return <class 'bytes'> piCtory Datei""" @return <class 'bytes'> piCtory Datei"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("read of closed file") raise ValueError("read of closed file")
with self.__socklock: with self.__socklock:
self._slavesock.send(_syspictory) self._slavesock.send(_syspictory)
byte_buff = bytearray() byte_buff = bytearray()
while not self.__sockend: while not self.__sockend.is_set():
data = self._slavesock.recv(1024) data = self._slavesock.recv(256)
byte_buff += data byte_buff += data
if data.find(b'\x04') >= 0: if data.find(b'\x04') >= 0:
self.__trigger = True
# NOTE: Nur suchen oder Ende prüfen? # NOTE: Nur suchen oder Ende prüfen?
return byte_buff[:-1] return byte_buff[:-1]
self.__sockerr.set() self.__sockerr.set()
raise IOError("readpictory error on network") raise IOError("readpictory error on network")
self.__trigger = True
def run(self): def run(self):
"""Handler fuer Synchronisierung.""" """Handler fuer Synchronisierung."""
while not self.__sockend: while not self.__sockend.is_set():
# Bei Fehlermeldung neu verbinden # Bei Fehlermeldung neu verbinden
if self.__sockerr.is_set(): if self.__sockerr.is_set():
self._connect() self._connect()
if self.__sockerr.is_set():
# Verhindert bei Scheitern 100% CPU last
self.__sockend.wait(self.__waitsync)
else: else:
# Kein Fehler aufgetreten, sync durchführen wenn socket frei # Kein Fehler aufgetreten, sync durchführen wenn socket frei
@@ -380,7 +411,7 @@ class NetFH(Thread):
def seek(self, position): def seek(self, position):
"""Springt an angegebene Position. """Springt an angegebene Position.
@param position An diese Position springen""" @param position An diese Position springen"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("seek of closed file") raise ValueError("seek of closed file")
self.__position = int(position) self.__position = int(position)
@@ -388,10 +419,13 @@ class NetFH(Thread):
"""Konfiguriert Dirtybytes fuer Prozessabbild bei Verbindungsfehler. """Konfiguriert Dirtybytes fuer Prozessabbild bei Verbindungsfehler.
@param positon Startposition zum Schreiben @param positon Startposition zum Schreiben
@param dirtybytes <class 'bytes'> die geschrieben werden sollen""" @param dirtybytes <class 'bytes'> die geschrieben werden sollen"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("I/O operation on closed file") raise ValueError("I/O operation on closed file")
with self.__socklock: error = False
try:
self.__socklock.acquire()
self._slavesock.sendall( self._slavesock.sendall(
b'\x01EY' + b'\x01EY' +
position.to_bytes(length=2, byteorder="little") + position.to_bytes(length=2, byteorder="little") +
@@ -406,24 +440,35 @@ class NetFH(Thread):
# ACL prüfen und ggf Fehler werfen # ACL prüfen und ggf Fehler werfen
self.__check_acl(check) self.__check_acl(check)
self.__sockerr.set()
raise IOError("set dirtybytes error on network") raise IOError("set dirtybytes error on network")
except AclException:
raise
except Exception:
error = True
finally:
self.__socklock.release()
# Daten erfolgreich übernehmen # Daten immer übernehmen
self.__dictdirty[position] = dirtybytes self.__dictdirty[position] = dirtybytes
if error:
# Fehler nach übernahme der Daten auslösen um diese zu setzen
self.__sockerr.set()
self.__trigger = True self.__trigger = True
def set_timeout(self, value): def set_timeout(self, value):
"""Setzt Timeoutwert fuer Verbindung. """Setzt Timeoutwert fuer Verbindung.
@param value Timeout in Millisekunden""" @param value Timeout in Millisekunden"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("I/O operation on closed file") raise ValueError("I/O operation on closed file")
# Timeoutwert verarbeiten (könnte Exception auslösen) # Timeoutwert verarbeiten (könnte Exception auslösen)
self.__set_systimeout(value) self.__set_systimeout(value)
with self.__socklock: try:
self.__socklock.acquire()
self._slavesock.send( self._slavesock.send(
b'\x01CF' + b'\x01CF' +
value.to_bytes(length=2, byteorder="little") + value.to_bytes(length=2, byteorder="little") +
@@ -431,15 +476,18 @@ class NetFH(Thread):
) )
check = self._slavesock.recv(1) check = self._slavesock.recv(1)
if check != b'\x1e': if check != b'\x1e':
self.__sockerr.set()
raise IOError("set timeout error on network") raise IOError("set timeout error on network")
except Exception:
self.__sockerr.set()
finally:
self.__socklock.release()
self.__trigger = True self.__trigger = True
def tell(self): def tell(self):
"""Gibt aktuelle Position zurueck. """Gibt aktuelle Position zurueck.
@return int aktuelle Position""" @return int aktuelle Position"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("I/O operation on closed file") raise ValueError("I/O operation on closed file")
return self.__position return self.__position
@@ -447,7 +495,7 @@ class NetFH(Thread):
"""Daten ueber das Netzwerk schreiben. """Daten ueber das Netzwerk schreiben.
@param bytebuff Bytes zum schreiben @param bytebuff Bytes zum schreiben
@return <class 'int'> Anzahl geschriebener bytes""" @return <class 'int'> Anzahl geschriebener bytes"""
if self.__sockend: if self.__sockend.is_set():
raise ValueError("write to closed file") raise ValueError("write to closed file")
if self.__flusherr: if self.__flusherr:
@@ -469,6 +517,7 @@ class NetFH(Thread):
closed = property(get_closed) closed = property(get_closed)
name = property(get_name) name = property(get_name)
reconnecting = property(get_reconnecting)
timeout = property(get_timeout, set_timeout) timeout = property(get_timeout, set_timeout)
@@ -579,6 +628,11 @@ class RevPiNetIO(_RevPiModIO):
mynh.close() mynh.close()
return jloads(byte_buff.decode("utf-8")) return jloads(byte_buff.decode("utf-8"))
def get_reconnecting(self):
"""Interner reconnect aktiv wegen Netzwerkfehlern.
@return True, wenn reconnect aktiv"""
return self._myfh.reconnecting
def net_cleardefaultvalues(self, device=None): def net_cleardefaultvalues(self, device=None):
"""Loescht Defaultwerte vom PLC Slave. """Loescht Defaultwerte vom PLC Slave.
@param device nur auf einzelnes Device anwenden, sonst auf Alle""" @param device nur auf einzelnes Device anwenden, sonst auf Alle"""
@@ -646,6 +700,8 @@ class RevPiNetIO(_RevPiModIO):
dev._offset + dev._slc_out.start, dirtybytes dev._offset + dev._slc_out.start, dirtybytes
) )
reconnecting = property(get_reconnecting)
class RevPiNetIOSelected(RevPiNetIO): class RevPiNetIOSelected(RevPiNetIO):