def starting(self): """Start the TCP client and optionally connect to host/post.""" super(TCPClient, self).starting() server_host = expand(self.cfg.host, self.context) server_port = expand(self.cfg.port, self.context, int) self._client = Client(host=server_host, port=server_port) if self.cfg.connect_at_start: self.connect()
def test_basic_server_client(): # Start server server = Server() server.bind() assert server._listening is False server.serve() assert server._listening is True assert server.active_connections == 0 assert server.accepted_connections == 0 # No connection to accept assert server.accept_connection(timeout=0) == -1 # Connect client client = Client(host=server.ip, port=server.port) client.connect() # Server accepts connection conn_idx = server.accept_connection() assert conn_idx == 0 assert server.active_connections == 1 assert server.accepted_connections == 1 # Client sends message msg = b'Hello' _, size = client.send(msg) assert size == len(msg) # Server receives received = server.receive(size, conn_idx=conn_idx) assert received == msg # Server sends reply msg = b'World' server.send(msg, conn_idx) received = client.receive(1024) assert received == msg client.close() server.close()
def test_two_clients(): server = Server() server.bind() server.serve() client1 = Client(host=server.ip, port=server.port) client2 = Client(host=server.ip, port=server.port) # Client 1 connect and send message client1.connect() conn_1 = server.accept_connection(5) msg1 = b'Hello!' _, size1 = client1.send(msg1) # Client 2 connect and send message before server received msg from 1 client2.connect() conn_2 = server.accept_connection(5) msg2 = b'Hey' _, size2 = client2.send(msg2) # Server responds to 1 assert server.receive(size1, conn_idx=conn_1) == msg1 resp1 = b'Yo1' server.send(resp1, conn_idx=conn_1) # Server responds to 2 assert server.receive(size2, conn_idx=conn_2) == msg2 resp2 = b'Yo2' server.send(resp2, conn_idx=conn_2) # Clients receiving responses assert client1.recv(1024) == resp1 assert client2.recv(1024) == resp2 client1.close() client2.close() server.close()
class TCPClient(Driver): """ TCP client driver. This is built on top of the :py:class:`testplan.common.utils.sockets.client.Client` class, which provides equivalent functionality and may be used outside of MultiTest. :param name: Name of TCPClient. :type name: ``str`` :param host: Target host name. This can be a :py:class:`~testplan.common.utils.context.ContextValue` and will be expanded on runtime. :type host: ``str`` :param port: Target port number. This can be a :py:class:`~testplan.common.utils.context.ContextValue` and will be expanded on runtime. :type port: ``int`` :param interface: Interface to bind to. :type interface: ``NoneType`` or ``tuple``(``str, ``int``) :param connect_at_start: Connect to server on start. Default: True :type connect_at_start: ``bool`` Also inherits all :py:class:`~testplan.testing.multitest.driver.base.Driver` options. """ CONFIG = TCPClientConfig def __init__(self, name, host, port, interface=None, connect_at_start=(True), **options): options.update(self.filter_locals(locals())) super(TCPClient, self).__init__(**options) self._host = None self._port = None self._client = None @property def host(self): """Target host name.""" return self._host @property def port(self): """Client port number assigned.""" return self._port def connect(self): """ Connect client. """ self._client.connect() self._host, self._port = self._client.address def send_text(self, msg, standard="utf-8"): """ Encodes to bytes and calls :py:meth:`TCPClient.send <testplan.testing.multitest.driver.tcp.client.TCPClient.send>`. """ return self.send(bytes(msg.encode(standard))) def send(self, msg): """ Sends bytes. :param msg: Message to be sent :type msg: ``bytes`` :return: Number of bytes sent :rtype: ``int`` """ return self._client.send(msg)[1] def send_tsp(self, msg): """ Sends bytes and returns also timestamp sent. :param msg: Message to be sent :type msg: ``bytes`` :return: Timestamp when msg sent (in microseconds from epoch) and number of bytes sent :rtype: ``tuple`` of ``long`` and ``int`` """ return self._client.send(msg) def receive_text(self, standard="utf-8", **kwargs): """ Calls :py:meth:`TCPClient.receive <testplan.testing.multitest.driver.tcp.server.TCPClient.receive>` and decodes received bytes. """ return self.receive(**kwargs).decode(standard) def receive(self, size=1024, timeout=30): """Receive bytes from the given connection.""" received = None timeout_info = TimeoutExceptionInfo() try: received = self._client.receive(size, timeout=timeout or 0) except socket.timeout: if timeout is not None: raise TimeoutException( "Timed out waiting for message on {0}. {1}".format( self.cfg.name, timeout_info.msg())) return received def reconnect(self): """Client reconnect.""" self._client.close() self.connect() def starting(self): """Start the TCP client and optionally connect to host/post.""" super(TCPClient, self).starting() server_host = expand(self.cfg.host, self.context) server_port = expand(self.cfg.port, self.context, int) self._client = Client(host=server_host, port=server_port) if self.cfg.connect_at_start: self.connect() def stopping(self): """Close the client connection.""" super(TCPClient, self).stopping() if self._client: self._client.close() def aborting(self): """Abort logic that stops the client.""" if self._client: self._client.close()