IPyC Examples and Uses¶
When attempting to communicate between any host and client, ensure the host runs first. That is, the host must be listening prior to any client connection.
All examples listed here are also in the examples directory with the installed module. You can view them on the GitHub or browse to them using your file explorer to view and interact with.
Hello World¶
Host¶
from ipyc import AsyncIPyCHost, AsyncIPyCLink
host = AsyncIPyCHost()
@host.on_connect
async def on_connection(connection: AsyncIPyCLink):
print('We got a new connection!')
while connection.is_active():
message = await connection.receive()
if message:
print(f"The other side says: {message}")
print("The connection was closed!")
print('Starting to wait for connections!')
host.run()
Client¶
import asyncio
from ipyc import AsyncIPyCClient
async def hello_world():
print('Connecting to the host...', end=' ')
client = AsyncIPyCClient()
link = await client.connect()
print('connected!\nSending "Hello World!"...', end=' ')
await link.send("Hello World!")
print('sent!\nClosing connection...', end=' ')
await client.close()
print('closed!')
loop = asyncio.get_event_loop()
loop.run_until_complete(hello_world())
Explanation¶
This simple set of scripts allows the client to send the host a string that says “Hello World”. Since a string is a pyhton builtin, no custom serializer is needed, and can be send natively. Additionally, it is assumed that these two applications are run on the same machine, since no IP address was supplied to the host and client classes. If however these are on two different systems, an IP address must be supplied for the host and client.
Custom Transport¶
Sometimes sending builtins is not enough. Typically classes are built from builtins, but are not natively able to be “stringified”. Because of this, IPyC allows for you to define a custom serializer and deserializer for your custom classes. These methods can be built into the classes themselves or expressed outside class scope.
The following example will show how you can use IPyC to transport the following class:
class CustomObject:
def __init__(self, arg1: int, arg2: float, arg3: str, arg4: set):
self.a1 = arg1
self.a2 = arg2
self.a3 = arg3
self.a4 = arg4
def __str__(self):
return f"<CustomObject:a1={self.a1},a2={self.a2},a3={self.a3},a4={self.a4}>"
# Define a serializer that returns a string/str representation of the object
def serialize(self):
return f"{self.a1}|{self.a2}|{self.a3}|{self.a4}"
# Define a deserializer that undoes what the serializer did and returns the object
@staticmethod
def deserialize(serialization):
a1, a2, a3, a4 = serialization.split('|')
return CustomObject(int(a1), float(a2), str(a3), eval(a4))
Host¶
from ipyc import IPyCHost, IPyCLink, IPyCSerialization
from custom_object import CustomObject
host = IPyCHost()
IPyCSerialization.add_custom_deserialization(CustomObject, CustomObject.deserialize)
print('Starting to wait for connections!')
while not host.is_closed():
connection = host.wait_for_client()
print('We got a new connection!')
while connection.is_active():
message = connection.receive()
if message:
print(f"The connection sent us a {type(message)} and it was {message}")
print(message.a1, message.a2, message.a3, message.a4)
print("The connection was closed!")
Client¶
from ipyc import IPyCClient, IPyCSerialization
from custom_object import CustomObject
custom_object = CustomObject(42, 3.1415926535897932, "Lorem ipsum dolor sit amet", {'s', 'e', 't'})
IPyCSerialization.add_custom_serialization(CustomObject, CustomObject.serialize)
print('Connecting to the host...', end=' ')
client = IPyCClient()
link = client.connect()
print(f'connected!\nSending {custom_object}...', end=' ')
link.send(custom_object)
print('sent!\nClosing connection...', end=' ')
client.close()
print('closed!')
Explanation¶
This set of scripts allows the client to send the host a class object. Note however not all objects are able to be serialized or deserialized; examples of such are stateful connection objects, memory bound objects, and system specific structures.