OneClientServer¶
- class lsst.ts.tcpip.OneClientServer(host: str | None, port: int | None, log: Logger, connect_callback: Callable[[BaseClientOrServer], Awaitable[None]] | None = None, monitor_connection_interval: float = 0.1, name: str = '', encoding: str = 'utf-8', terminator: bytes = b'\r\n', **kwargs: Any)¶
Bases:
BaseClientOrServerA TCP/IP socket server that serves a single client.
If additional clients try to connect, they are rejected.
- Parameters:
- port
int IP port for this server. If 0 then randomly pick an available port (or ports, if listening on multiple sockets). 0 is strongly recommended for unit tests.
- host
strorNone IP address for this server. Common values include
DEFAULT_LOCALHOST,LOCALHOST_IPV4to force IPV4 orLOCALHOST_IPV6for IPV6. IfNonethen bind to all network interfaces (e.g. listen on an IPv4 socket and an IPv6 socket). Warning:Nonecan cause trouble withport=0; seeportin the Attributes section for more information.- log
logging.Logger Logger.
- connect_callbackcallable or
None, optional Asynchronous or (deprecated) synchronous function to call when a client connects or disconnects. If the other end (client) closes the connection, it may take
monitor_connection_intervalseconds or longer to notice. The function receives one argument: thisOneClientServer.- monitor_connection_interval
float, optional Interval between checking if the connection is still alive (seconds). Defaults to DEFAULT_MONITOR_CONNECTION_INTERVAL. If ≤ 0 then do not monitor the connection at all. Monitoring is only useful if you do not regularly read from the reader using the read methods of this class (or copying what they do to detect and report hangups).
- name
str, optional Name used for log messages, e.g. “Commands” or “Telemetry”.
- encoding
str - The encoding used by
read_strandwrite_str,read_json, and
write_json.
- The encoding used by
- terminator
bytes - The terminator used by
read_strandwrite_str,read_json, and
write_json.
- The terminator used by
- **kwargs
dict[str,typing.Any] Additional keyword arguments for
asyncio.start_server, beyond host and port.
- port
- Attributes:
- host
str|None IP address; the
hostconstructor argument.- port
int The port on which this server is running.
If you specify port=0 and the server is only listening on one socket, then the port attribute is set to the randomly chosen port. However, if the server is listening on more than one socket, the port is ambiguous (since each socket will have a different port) and will be left at 0; in that case you will have to examine server.sockets to determine the port you want.
To make the server listen on only one socket with port=0, specify the host as a string instead of None. For example:
IP4:
host=LOCALHOST_IPV4, port=0IP6:
host="::", port=0
An alternative that allows host=None is to specify family as
socket.AF_INETfor IPv4, orsocket.AF_INET6for IPv6.- connected_task
asyncio.Future Future that is set done when a client connects. You may set replace it with a new
asyncio.Futureif you want to detect when another connection is made after the current client disconnects.- plus…
Attributes provided by parent class
BaseClientOrServer.
- host
Notes
See tests/test_example.py for an example.
Always wait for
start_taskafter constructing an instance, before using the instance. This indicates that the server has started listening for a connection.You may wait for
connected_taskto wait until a client connects.This class provides high-level read and write methods that monitor the connection (to call
connect_callbackas needed) and reject any attempt to read or write if not connected. Please use them.Can be used as an async context manager, which may be useful for unit tests.
Attributes Summary
Return True if self._reader and self._writer are connected.
Methods Summary
Close the connected client socket, if any.
Call self.__connect_callback.
close()Close socket server and client socket, and set done_task done.
Close the connected client socket, if any.
read(n)Read up to n bytes.
read_into(struct)Read binary data from a stream reader into a
ctypes.Structure.Read JSON data.
read_str()Read and decode a terminated str; strip the terminator.
readexactly(n)Read exactly n bytes.
readline()Read a sequence of bytes ending with
\n.readuntil([separator])Read one line, where “line” is a sequence of bytes ending with
separator.start(**kwargs)Start the TCP/IP server.
write(data)Write data and call
drain.write_from(*structs)Write binary data from one or more
ctypes.Structures.write_json(data)Write data in JSON format.
write_str(line)Encode, terminate, and write a str.
writelines(lines)Write an iterable of bytes and call
drain.Attributes Documentation
- connected¶
Return True if self._reader and self._writer are connected.
Note: if the other end drops the connection and if you are not trying to read data (e.g. in a background loop), then it takes the operating system awhile to realize the connection is lost. So this can return true for some unknown time after the connection has been dropped.
Methods Documentation
- async basic_close_client() None¶
Close the connected client socket, if any.
Also:
Reset
self.connected_taskto a new Future.Call connect_callback, if a client was connected.
Unlike
close_client, this does not touchself.should_be_connected.Always safe to call.
- async call_connect_callback() None¶
Call self.__connect_callback.
This is always safe to call. It only calls the callback function if that function is not None and if the connection state has changed since the last time this method was called.
- async close() None¶
Close socket server and client socket, and set done_task done.
Call connect_callback if a client was connected.
Always safe to call.
- async close_client() None¶
Close the connected client socket, if any.
Also:
Set
self.should_be_connectedfalse.Reset
self.connected_taskto a new Future.Call connect_callback, if a client was connected.
Always safe to call.
- async read(n: int) bytes¶
Read up to n bytes.
- Parameters:
- n
int The number of bytes to read. If -1 then block until the other end closes its writer, then return all data seen.
- n
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
- async read_into(struct: Structure) None¶
Read binary data from a stream reader into a
ctypes.Structure.- Parameters:
- struct
ctypes.Structure Structure to set.
- struct
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
asyncio.IncompleteReadErrorIf EOF is reached before
nbytes can be read. Use theIncompleteReadError.partialattribute to get the partially read data.
- async read_json() Any¶
Read JSON data.
Read the data with
read_strand return the json-decoded result.- Returns:
- data
typing.Any Data decoded from JSON.
- data
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
asyncio.IncompleteReadErrorIf EOF is reached before the complete separator is found and the internal buffer is reset.
LimitOverrunErrorIf the amount of data read exceeds the configured stream lmit. The data is left in the internal buffer and can be read again.
TypeErrorIf the data are of a type that cannot be decoded from JSON.
json.JSONDecodeErrorIf the data cannot be decoded from JSON.
- async read_str() str¶
Read and decode a terminated str; strip the terminator.
Read until
self.terminator, strip the terminator, and decode the data asself.encodingwith strict error handling.- Returns:
- line
str Line of data, as a str with the terminator stripped.
- line
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
asyncio.IncompleteReadErrorIf EOF is reached before the complete separator is found and the internal buffer is reset.
LimitOverrunErrorIf the amount of data read exceeds the configured stream lmit. The data is left in the internal buffer and can be read again.
UnicodeErrorIf decoding fails.
- async readexactly(n: int) bytes¶
Read exactly n bytes.
- Parameters:
- n
int The number of bytes to read.
- n
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
asyncio.IncompleteReadErrorIf EOF is reached before
nbytes can be read. Use theIncompleteReadError.partialattribute to get the partially read data.
- async readline() bytes¶
Read a sequence of bytes ending with
\n.If EOF is received and
\nwas not found, the method returns partially read data.- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
- async readuntil(separator: bytes = b'\n') bytes¶
Read one line, where “line” is a sequence of bytes ending with
separator.Read data from the stream until separator is found.
On success, the data and separator will be removed from the internal buffer (consumed). Returned data will include the separator at the end.
See also
read_str, which is more convenient for most use cases.- Parameters:
- separator
bytes The desired separator. The default matches the standard library, rather than using
terminator.
- separator
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
asyncio.IncompleteReadErrorIf EOF is reached before the complete separator is found and the internal buffer is reset.
LimitOverrunErrorIf the amount of data read exceeds the configured stream lmit. The data is left in the internal buffer and can be read again.
- async start(**kwargs: Any) None¶
Start the TCP/IP server.
This is called automatically by the constructor, and is not intended to be called by the user. It is a public method so that subclasses can override it.
- Parameters:
- **kwargs
dict[str,typing.Any] Additional keyword arguments for
asyncio.start_server, beyond host and port.
- **kwargs
- Raises:
RuntimeErrorIf start has already been called and has successfully constructed a server.
- async write(data: bytes) None¶
Write data and call
drain.- Parameters:
- data
bytes The data to write.
- data
- Raises:
ConnectionErrorIf
self.connectedfalse before writing begins.
- async write_from(*structs: Structure) None¶
Write binary data from one or more
ctypes.Structures.- Parameters:
- structs
list[ctypes.Structure] Structures to write.
- structs
- Raises:
ConnectionErrorIf
self.connectedfalse before writing begins.
- async write_json(data: Any) None¶
Write data in JSON format.
Encode the data as json and write the result with
write_str.- Parameters:
- data
any The data to be written, typically a dict, but any json-encodable data is acceptable.
- data
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
UnicodeErrorIf encoding fails.
json.JSONEncodeErrorIf the data cannot be json-encoded.
- async write_str(line: str) None¶
Encode, terminate, and write a str.
Encode the str as
self.encodingwith strict error handling, and appendself.terminator.- Parameters:
- line
str The line of data to be written.
- line
- Raises:
ConnectionErrorIf the connection is lost before, or while, reading.
UnicodeErrorIf encoding fails.
- async writelines(lines: Iterable) None¶
Write an iterable of bytes and call
drain.- Parameters:
- lines
collections.abc.Iterable[bytes] The data to write, as an iterable collection of
bytes.
- lines
- Raises:
ConnectionErrorIf
self.connectedfalse before writing begins.