def shutdown_request( self ): '''The default SocketServer.shutdown_request does send a shutdown(socket.SHUT_WR), but does NOT wait for the socket to drain before closing it, potentially leaving the kernel socket dirty (filled with unclaimed data; at least the client's EOF). Drain the socket, then close it. Ignores ENOTCONN (and other) socket.error if socket is already closed. ''' log.detail( "Modbus/TCP client socket shutdown/drain %s", self.client_address ) network.drain( self.request, timeout=self.drain, close=False ) self.close_request()
def shutdown_request(self): '''The default SocketServer.shutdown_request does send a shutdown(socket.SHUT_WR), but does NOT wait for the socket to drain before closing it, potentially leaving the kernel socket dirty (filled with unclaimed data; at least the client's EOF). Drain the socket, then close it. Ignores ENOTCONN (and other) socket.error if socket is already closed. ''' log.detail("Modbus/TCP client socket shutdown/drain %s", self.client_address) network.drain(self.request, timeout=self.drain, close=False) self.close_request()
def echo_cli( number, reps ): log.normal( "Echo Client %3d connecting... PID [%5d]", number, os.getpid() ) conn = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) conn.connect( echo.address ) log.detail( "Echo Client %3d connected", number ) sent = b'' rcvd = b'' try: # Send messages and collect replies 'til done (or incoming EOF). Then, shut down # outgoing half of socket to drain server and shut down server. eof = False for r in range( reps ): msg = ("Client %3d, rep %d\r\n" % ( number, r )).encode() log.detail("Echo Client %3d send: %5d: %s", number, len( msg ), cpppo.reprlib.repr( msg )) sent += msg while len( msg ) and not eof: out = min( len( msg ), random.randrange( *charrange )) conn.send( msg[:out] ) msg = msg[out:] # Await inter-block chardelay if output remains, otherwise await final response # before dropping out to shutdown/drain/close. If we drop out immediately and send # a socket.shutdown, it'll sometimes deliver a reset to the server end of the # socket, before delivering the last of the data. rpy = network.recv( conn, timeout=chardelay if len( msg ) else draindelay ) if rpy is not None: eof = not len( rpy ) log.detail( "Echo Client %3d recv: %5d: %s", number, len( rpy ), "EOF" if eof else cpppo.reprlib.repr( rpy )) rcvd += rpy if eof: break log.normal( "Echo Client %3d done; %s", number, "due to EOF" if eof else "normal termination" ) except KeyboardInterrupt as exc: log.warning( "Echo Client %3d terminated: %r", number, exc ) except Exception as exc: log.warning( "Echo Client %3d failed: %r\n%s", number, exc, traceback.format_exc() ) finally: # One or more packets may be in flight; wait 'til we timeout/EOF. This shuts down conn. rpy = network.drain( conn, timeout=draindelay ) log.info( "Echo Client %3d drain %5d: %s", number, len( rpy ) if rpy is not None else 0, cpppo.reprlib.repr( rpy )) if rpy is not None: rcvd += rpy # Count the number of success/failures reported by the Echo client threads failed = not ( rcvd == sent ) if failed: log.warning( "Echo Client %3d failed: %s != %s sent", number, cpppo.reprlib.repr( rcvd ), cpppo.reprlib.repr( sent )) log.info( "Echo Client %3d exited", number ) return failed
def tnet_cli(number, tests=None): log.info("%3d client connecting... PID [%5d]", number, os.getpid()) conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) conn.connect(tnet.address) log.info("%3d client connected", number) rcvd = '' try: eof = False for t in tests: msg = tnetstrings.dump(t) while len(msg) and not eof: out = min(len(msg), random.randrange(*charrange)) log.info("Tnet Client %3d send: %5d/%5d: %s", number, out, len(msg), cpppo.reprlib.repr(msg[:out])) conn.sendall(msg[:out]) msg = msg[out:] # Await inter-block chardelay if output remains, otherwise await # final response before dropping out to shutdown/drain/close. # If we drop out immediately and send a socket.shutdown, it'll # sometimes deliver a reset to the server end of the socket, # before delivering the last of the data. rpy = network.recv( conn, timeout=chardelay if len(msg) else draindelay) if rpy is not None: eof = not len(rpy) log.info("Tnet Client %3d recv: %5d: %s", number, len(rpy), "EOF" if eof else cpppo.reprlib.repr(rpy)) rcvd += rpy.decode("utf-8") if eof: break log.normal("Tnet Client %3d done; %s", number, "due to EOF" if eof else "normal termination") except KeyboardInterrupt as exc: log.normal("%3d client terminated: %r", number, exc) except Exception as exc: log.warning("%3d client failed: %r\n%s", number, exc, traceback.format_exc()) finally: # One or more packets may be in flight; wait 'til we timeout/EOF rpy = network.drain(conn, timeout=draindelay) log.info("Tnet Client %3d drain %5d: %s", number, len(rpy) if rpy is not None else 0, cpppo.reprlib.repr(rpy)) if rpy is not None: rcvd += rpy.decode("utf-8") # Count the number of successfully matched JSON decodes successes = 0 i = 0 for i, (t, r) in enumerate(zip(tests, rcvd.split('\n\n'))): e = json.dumps(t) log.info("%3d test #%3d: %32s --> %s", number, i, cpppo.reprlib.repr(t), cpppo.reprlib.repr(e)) if r == e: successes += 1 else: log.warning("%3d test #%3d: %32s got %s", number, i, cpppo.reprlib.repr(t), cpppo.reprlib.repr(e)) failed = successes != len(tests) if failed: log.warning("%3d client failed: %d/%d tests succeeded", number, successes, len(tests)) log.info("%3d client exited", number) return failed
def tnet_cli( number, tests=None ): log.info( "%3d client connecting... PID [%5d]", number, os.getpid() ) conn = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) conn.connect( tnet.address ) log.info( "%3d client connected", number ) rcvd = '' try: eof = False for t in tests: msg = tnetstrings.dump( t ) log.normal( "Tnet Client %3d send: %5d: %s (from data: %s)", number, len( msg ), cpppo.reprlib.repr( msg ), cpppo.reprlib.repr( t )) while len( msg ) and not eof: out = min( len( msg ), random.randrange( *charrange )) conn.send( msg[:out] ) msg = msg[out:] # Await inter-block chardelay if output remains, otherwise await # final response before dropping out to shutdown/drain/close. # If we drop out immediately and send a socket.shutdown, it'll # sometimes deliver a reset to the server end of the socket, # before delivering the last of the data. rpy = network.recv( conn, timeout=chardelay if len( msg ) else draindelay ) if rpy is not None: eof = not len( rpy ) log.info( "Tnet Client %3d recv: %5d: %s", number, len( rpy ), "EOF" if eof else cpppo.reprlib.repr( rpy )) rcvd += rpy.decode( "utf-8" ) if eof: break log.normal( "Tnet Client %3d done; %s", number, "due to EOF" if eof else "normal termination" ) except KeyboardInterrupt as exc: log.normal( "%3d client terminated: %r", number, exc ) except Exception as exc: log.warning( "%3d client failed: %r\n%s", number, exc, traceback.format_exc() ) finally: # One or more packets may be in flight; wait 'til we timeout/EOF rpy = network.drain( conn, timeout=draindelay ) log.info( "Tnet Client %3d drain %5d: %s", number, len( rpy ) if rpy is not None else 0, cpppo.reprlib.repr( rpy )) if rpy is not None: rcvd += rpy.decode( "utf-8" ) # Count the number of successfully matched JSON decodes successes = 0 i = 0 for i, (t, r) in enumerate( zip( tests, rcvd.split( '\n\n' ))): e = json.dumps( t ) log.info( "%3d test #%3d: %32s --> %s", number, i, cpppo.reprlib.repr( t ), cpppo.reprlib.repr( e )) if r == e: successes += 1 else: log.warning( "%3d test #%3d: %32s got %s", number, i, cpppo.reprlib.repr( t ), cpppo.reprlib.repr( e )) failed = successes != len( tests ) if failed: log.warning( "%3d client failed: %d/%d tests succeeded", number, successes, len( tests )) log.info( "%3d client exited", number ) return failed