Client-server subpackage (ska_ser_devices.client_server)
This subpackage supports client-server communication.
A key design element is that received data is provided to the application layer via a bytestring iterator:
Receipt of an application payload may be split across multiple buffers, and the manner by which the application layer decides that it has received enough bytes to comprise a full application payload is exclusively determined by the application.
For example, the application layer might deal in “lines”, and receiving a “line” might involve continually receiving bytestrings until a line terminator character sequence such as “rn” is encountered.
Using TCP as an example for how transport protocol details (e.g. socket reads) are commonly mixed with application-level decision logic, the concatenation of bytestrings into an application payload is typically implemented like:
data = my_socket.recv(1024)
while not data.endswith(b"\r\n"):
data = data + my_socket.recv(1024)
Instead, this module handles this situation by passing a bytestring iterator to the application layer. Thus, it is the application layer’s job to iterate over bytestrings until it has constructed a full application payload. Meanwhile, the transport protocol details remain hidden, and the application remains agnostic of any transport mechanism.
data = next(bytes_iterator)
while not data.endswith(b"\r\n"):
data = data + next(bytes_iterator)
- class ska_ser_devices.client_server.ApplicationClient(bytes_client, request_marshaller, response_unmarshaller)
An application-layer client.
It uses an underlying transport-layer client (such as a TCP client), but requests are application payloads rather than bytestrings. These must be marshalled into bytestrings before sending to the server. When a response is received from the server, the received bytes are unmarshalled into an application payload which is returned to the caller. Thus, the caller deals only in application payloads, and does not know any details about how the transport layer transmits those payloads,
- __enter__()
Establish a new connection, and enter the new session context.
- Return type
ApplicationClientSession
[TypeVar
(RequestPayloadT
),TypeVar
(ResponsePayloadT
)]- Returns
access to the session context.
- __exit__(exc_type, exception, trace)
Exit method for “with” context.
- Parameters
exc_type (
Optional
[Type
[BaseException
]]) – the type of exception thrown in the with blockexception (
Optional
[BaseException
]) – the exception thrown in the with blocktrace (
Optional
[TracebackType
]) – a traceback
- Return type
- Returns
whether the exception (if any) has been fully handled by this method and should be swallowed i.e. not re-raised
- __init__(bytes_client, request_marshaller, response_unmarshaller)
Initialise a new instance.
- Parameters
bytes_client (
TransportClientProtocol
) – the bytes-level client to use.request_marshaller (
Callable
[[TypeVar
(RequestPayloadT
)],bytes
]) – a callable that marshalls application-layer request payloads into bytes.response_unmarshaller (
Callable
[[Iterator
[bytes
]],TypeVar
(ResponsePayloadT
)]) – a callable that unmarshalls byte into application-layer response payloads.
- __weakref__
list of weak references to the object (if defined)
- connect()
Establish a new connection.
- Return type
ApplicationClientSession
[TypeVar
(RequestPayloadT
),TypeVar
(ResponsePayloadT
)]- Returns
access to the new session.
- class ska_ser_devices.client_server.ApplicationClientSession(request_marshaller, response_unmarshaller, transport_session)
A class for representing and managing a session.
- __init__(request_marshaller, response_unmarshaller, transport_session)
Initialise a new session instance.
- Parameters
request_marshaller (
Callable
[[TypeVar
(RequestPayloadT
)],bytes
]) – a callable that marshalls application-layer request payloads into bytes.response_unmarshaller (
Callable
[[Iterator
[bytes
]],TypeVar
(ResponsePayloadT
)]) – a callable that unmarshalls byte into application-layer response payloads.transport_session (
TransportClientSessionProtocol
) – the underlying transport-layer session.
- __weakref__
list of weak references to the object (if defined)
- send(request)
Call the client with a request, for which no response is expected.
The client marshalls the request (an application payload) down to a bytestring, then hands the bytestring down to the bytestring TCP client for sending to the server.
- send_receive(request)
Call the client with a request, for which a response is expected.
The client marshalls the request (an application payload) down to a bytestring, then hands the bytestring down to the bytestring TCP client for sending to the server. Upon receive of a bytestring response, this client unmarshalls it into an application payload, which is returned to the caller.
- class ska_ser_devices.client_server.ApplicationServer(request_unmarshaller, response_marshaller, callback)
A server of application payloads.
It uses an underlying transport-layer server (such as a TCP server), but requests are unmarshalled into application-layer payloads before being delivered to the application-layer server backend. Responses from the server backend are application-layer payloads that this server marshals down to a bytestring and returns to the client. Thus, the server backend deals only in application payloads, and does not know any details about how the transport layer transmits those payloads.
- __call__(bytes_iterator)
Handle receipt of bytes from the transport layer.
When the transport layer server receives some bytes, it calls this callback with a bytestring iterator. This callback uses that iterator to ingest bytestrings until it has enough bytes to unmarshall them into a complete application payload. The payload is passed to the server backend. Once this callback receives a response from the backend, it marshalls that response down to a bytestring, and returns it to the transport-layer server for returning to the client.
- __init__(request_unmarshaller, response_marshaller, callback)
Initialise a new instance.
- Parameters
request_unmarshaller (
Callable
[[Iterator
[bytes
]],TypeVar
(RequestPayloadT
)]) – a callable that unmarshalls byte into application-layer request payloads.response_marshaller (
Callable
[[TypeVar
(ResponsePayloadT
)],bytes
]) – a callable that marshalls application-layer response payloads into bytescallback (
Callable
[[TypeVar
(RequestPayloadT
)],Optional
[TypeVar
(ResponsePayloadT
)]]) – callback to the application layer. When this server receives a request payload, it calls the application layer with the request, and expects to receive a response payload back.
- __weakref__
list of weak references to the object (if defined)
- class ska_ser_devices.client_server.FixedLengthBytesMarshaller(length, logger=None)
A bytes marshaller for bytestrings of fixed, known length.
- __init__(length, logger=None)
Initialise a new instance.
- __weakref__
list of weak references to the object (if defined)
- marshall(payload)
Marshall application-layer payload bytes into bytes to be transmitted.
This class simply appends the sentinel character sequence.
- Parameters
payload (
bytes
) – the application-layer payload bytes.- Return type
- Returns
the bytes to be transmitted.
- Raises
ValueError – if the received bytestring is not of the correct length
- unmarshall(bytes_iterator)
Unmarshall transmitted bytes into application-layer payload bytes.
This method is implemented to continually receive bytestrings until it receives a bytestring terminated by the sentinel. It then strips the sentinel off, and returns the rest.
- Parameters
bytes_iterator (
Iterator
[bytes
]) – an iterator of bytestrings received by the server- Return type
- Returns
the application-layer bytestring.
- Raises
ValueError – if the received bytestring is not of the correct length
- class ska_ser_devices.client_server.SentinelBytesMarshaller(sentinel, logger=None)
A bytes marshaller that marshalls and unmarshalls terminated bytestrings.
That is, the application-layer payload is a bytestring, the end of which is demarcated by a special character sequence. For example, the payload might be
A c-style string, terminated by the NUL character;
A line of text, terminated by an end-of-line sequence, such as “rn”.
A file, terminated by an EOF byte.
- __init__(sentinel, logger=None)
Initialise a new instance.
- __weakref__
list of weak references to the object (if defined)
- marshall(payload)
Marshall application-layer payload bytes into bytes to be transmitted.
This class simply appends the sentinel character sequence.
- unmarshall(bytes_iterator)
Unmarshall transmitted bytes into application-layer payload bytes.
This method is implemented to continually receive bytestrings until it receives a bytestring terminated by the sentinel. It then strips the sentinel off, and returns the rest.
- class ska_ser_devices.client_server.TcpClient(address, timeout=None, buffer_size=1024, logger=None)
A TCP client that operates at the bytestring level.
It handles client requests by sending the request bytes straight off to the server. However, when it receives a response, it creates a bytestring iterator and hands it up to the application layer, so that the application layer can receive as many bytestrings as it needs to constitute an application payload.
- __enter__()
Establish a new connection and enter the session context.
- Return type
- Returns
access to the session context
- __exit__(exc_type, exception, trace)
Exit method for “with” context.
- Parameters
exc_type (
Optional
[Type
[BaseException
]]) – the type of exception thrown in the with blockexception (
Optional
[BaseException
]) – the exception thrown in the with blocktrace (
Optional
[TracebackType
]) – a traceback
- Return type
- Returns
whether the exception (if any) has been fully handled by this method and should be swallowed i.e. not re-raised
- __init__(address, timeout=None, buffer_size=1024, logger=None)
Initialise a new instance.
- Parameters
address (
tuple
[str
|bytes
|bytearray
,int
]) – tuple consisting of the host name or IP address, and the port, of the server.timeout (
Optional
[float
]) – how long to wait when attempting to send or receive data, in seconds. If None, the socket blocks indefinitely.buffer_size (
int
) – maximum size of a bytestring.
- __weakref__
list of weak references to the object (if defined)
- connect()
Establish a new connection.
- Return type
- Returns
access to the established session.
- class ska_ser_devices.client_server.TcpClientSession(address, timeout, buffer_size, logger)
A class for representing and managing a TCP session.
- __init__(address, timeout, buffer_size, logger)
Establish a new session.
- Parameters
address (
tuple
[str
|bytes
|bytearray
,int
]) – a tuple consisting of the host name or IP address, and the port, of the server.timeout (
Optional
[float
]) – how long to wait when attempting to send or receive data, in seconds. If None, the socket blocks indefinitely.buffer_size (
int
) – maximum size of a bytestring.logger (
Logger
) – a python standard logger
- __weakref__
list of weak references to the object (if defined)
- request(request)
Initiate a new client request.
For example:
with tcp_client as session: bytes_iterator = session.request(request_bytes): response_bytes = next(bytes_iterator) if not response_bytes.endswith(b"\r\n"): response_bytes += next(bytes_iterator)
That is,
First enter into a session with the TCP server
Then send the request data.
- Since only the calling application can know
when it has received enough bytes for a complete response, the session context returns a bytestring iterator for the application layer to use to retrieve blocks of bytes. (In this example, the application layer knows that the response is terminated by “rn”, so it keeps receiving data until it encounters that sequence and the end of a block.)
Upon exiting the session context, the session is closed.
- Parameters
request (
bytes
) – request bytes.- Raises
ConnectionError – if the session socket is already closed.
- Return type
- Returns
a bytestring iterator.
- class ska_ser_devices.client_server.TcpServer(host, port, callback, buffer_size=1024, logger=None)
A TCP server that operates at the bytestring level.
It handles client requests by creating a bytestring iterator, and handing it up to the application layer, so that the application layer can receive as many bytestrings as it needs to constitute an application payload. When the application layer returns a response, that response is sent back to the client.
- __init__(host, port, callback, buffer_size=1024, logger=None)
Initialise a new instance.
- class ska_ser_devices.client_server.TelnetClient(address, timeout=None, logger=None)
A Telnet client.
It handles client requests by sending the request bytes straight off to the server. However, when it receives a response, it creates a bytestring iterator and hands it up to the application layer, so that the application layer can receive as many bytestrings as it needs to constitute an application payload.
- __enter__()
Establish a new connection and enter the session context.
- Return type
- Returns
access to the session context
- __exit__(exc_type, exception, trace)
Exit method for “with” context.
- Parameters
exc_type (
Optional
[Type
[BaseException
]]) – the type of exception thrown in the with blockexception (
Optional
[BaseException
]) – the exception thrown in the with blocktrace (
Optional
[TracebackType
]) – a traceback
- Return type
- Returns
whether the exception (if any) has been fully handled by this method and should be swallowed i.e. not re-raised
- __init__(address, timeout=None, logger=None)
Initialise a new instance.
- __weakref__
list of weak references to the object (if defined)
- connect()
Establish a new connection.
- Return type
- Returns
access to the established session.
- class ska_ser_devices.client_server.TelnetClientSession(address, timeout, logger)
A class for representing and managing a TCP session.
- __init__(address, timeout, logger)
Establish a new session.
- Parameters
- __weakref__
list of weak references to the object (if defined)
- request(request)
Initiate a new client request.
Call this method like
with telnet_client as session: byte_iterator = session.request(request_bytes): response_bytes = next(bytes_iterator) if not response_bytes.endswith(b"\r\n"): response_bytes += next(bytes_iterator)
That is,
First enter into a session with the Telnet server
Then send the request data.
- Since only the calling application can know
when it has received enough bytes for a complete response, the session context returns a bytestring iterator for the application layer to use to retrieve blocks of bytes. (In this example, the application layer knows that the response is terminated by “rn”, so it keeps receiving data until it encounters that sequence and the end of a block.)
Upon exiting the session context, the session is closed.
- class ska_ser_devices.client_server.TransportClientProtocol(*args, **kwargs)
Structural subtyping protocol for supported transport client.
In order for a transport client to be supported by this module, it must provide a connect method that establishes a session, and also implement a session context manager.
- __enter__()
Establish a connection, and enter a session context.
- Return type
- Returns
access to the session context.
- __exit__(exc_type, exception, trace)
Close the session and exit the session context.
- Parameters
exc_type (
Optional
[Type
[BaseException
]]) – the type of exception thrown in the with blockexception (
Optional
[BaseException
]) – the exception thrown in the with blocktrace (
Optional
[TracebackType
]) – a traceback
- Return type
- Returns
whether the exception (if any) has been fully handled by this method and should be swallowed i.e. not re-raised
- __init__(*args, **kwargs)
- __subclasshook__()
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
- __weakref__
list of weak references to the object (if defined)
- connect()
Establish a connection, and return access to the session.
- Return type
- Returns
access to the session context.
- class ska_ser_devices.client_server.TransportClientSessionProtocol(*args, **kwargs)
Structural subtyping protocol for supported transport client session.
In order for a transport session to be supported by this module, it must provide a request method that is implemented to
issue the client request, and
return an iterator, for use by the application layer to read as many bytestrings as necessary in order to construct the complete response payload.
- __init__(*args, **kwargs)
- __subclasshook__()
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
- __weakref__
list of weak references to the object (if defined)
- request(request)
Transact a client request.
Issue the request, and return an iterator for use by the application layer to read as many bytestrings as necessary to construct the complete response payload.