Communication System#
In LEADS, we provide a C/S communication system that is designed for the TCP protocol but can also be extended to other custom protocols. The philosophy of this system is that sending is the only active operation for both the server and the client. All other operations including receiving should be done passively through callback methods.
Server#
A Server is a pool that consists of multiple connections. Each connection runs
in a separate thread. You can specify to run the listener in the main thread or another thread when
starting the server.
Create a Server#
You should always use create_server() instead of the constructor.
from leads.comm import create_server, Server
port: int = 9000
server: Server = create_server(port)
This example creates a server listening on port 9000 (16900 by default). The port is not yet occupied as the server
has not been started.
Assign Callback Methods#
You can pass a Callback object when creating the server.
Tip
This is a subclass of CallbackChain. Learn more about it here.
from typing import override
from leads import L
from leads.comm import create_server, Server, Callback, Service, ConnectionBase
class MyCallback(Callback):
@override
def on_initialize(self, service: Service) -> None:
L.info("Initialized")
@override
def on_connect(self, service: Service, connection: ConnectionBase) -> None:
L.info("Connected")
@override
def on_receive(self, service: Service, msg: bytes) -> None:
L.info(msg.decode())
@override
def on_fail(self, service: Service, error: Exception) -> None:
L.error(repr(error))
@override
def on_disconnect(self, service: Service, connection: ConnectionBase) -> None:
L.info("Disconnected")
server: Server = create_server(callback=MyCallback())
Start the Server#
from leads.comm import create_server, Server, start_server
parallel: bool = True
server: Server = create_server()
start_server(server, parallel)
parrallel is False by default, meaning that it will run in the same thread in which you call
start_server(). If you wish not to block the main thread, set parallel to True
like the example above.
Broadcast to Clients#
To send a message to all clients, you can use broadcast() method.
from leads.comm import create_server, Server, start_server
server: Server = start_server(create_server())
server.broadcast(b"Hello world")
Get the Number of Connections#
from leads import L
from leads.comm import create_server, Server, start_server
server: Server = start_server(create_server())
L.info(str(server.num_connections()))
Close the Server#
from leads.comm import create_server, Server, start_server
server: Server = start_server(create_server())
server.close()
Client#
Unlike Server, a Client holds only one
connection.
Create a Client#
You should always use create_client() instead of the constructor.
from leads.comm import create_client, Client
port: int = 9000
client: Client = create_client(port)
You can use the same callback methods as the server.
from typing import override
from leads import L
from leads.comm import create_client, Client, Callback, Service, ConnectionBase
class MyCallback(Callback):
@override
def on_initialize(self, service: Service) -> None:
L.info("Initialized")
@override
def on_connect(self, service: Service, connection: ConnectionBase) -> None:
L.info("Connected")
@override
def on_receive(self, service: Service, msg: bytes) -> None:
L.info(msg.decode())
@override
def on_fail(self, service: Service, error: Exception) -> None:
L.error(repr(error))
@override
def on_disconnect(self, service: Service, connection: ConnectionBase) -> None:
L.info("Disconnected")
client: Client = create_client(callback=MyCallback())
Start the Client#
from leads.comm import create_client, Client, start_client
parallel: bool = True
address: str = "127.0.0.1"
client: Client = create_client()
start_client(address, client, parallel)
address can be a domain or an IP address.
parrallel is False by default, meaning that it will run in the same thread in which you call
start_client(). If you wish not to block the main thread, set parallel to True
like the example above.
Send a Message#
from leads.comm import create_client, Client, start_client
address: str = "127.0.0.1"
client: Client = start_client(address, create_client())
client.send(b"Hello world")
Close the Client#
from leads.comm import create_client, Client, start_client
address: str = "127.0.0.1"
client: Client = start_client(address, create_client())
client.close()
Connection#
ConnectionBase is the abstract base class of
Connection. ConnectionBase provides
a set of tools to parse the stream into sentences and deal with the remainder with ease, whereas
Connection implements the abstract methods and specifies TCP as the underlying
protocol.
The fundamental of the system is built on ConnectionBase, not
Connection. Therefore, you can use any implementation of
ConnectionBase to suit other protocols. Our serial communication system is a
perfect example. See SerialConnection.
Important
Server and Client do not support custom
connections. They are hardcoded to use Connection. If you have a custom
implementation, you need to build your own server or client from Entity like
ArduinoProto in our case.