ENet Hello World¶
A server listens on a port; a client connects to it; both call
EnetHost.service() regularly to move packets and receive events. The
following is the whole of it, in one process for the sake of the example.
from acron.core import Datagram, DatagramIterator
from acron.enet import EnetHost, EnetEvent
server = EnetHost.create_server(5000, peer_count=32, channel_limit=2)
if server is None:
raise RuntimeError("could not bind port 5000")
client = EnetHost.create_client(peer_count=4, channel_limit=2)
peer = client.connect("127.0.0.1", 5000)
def pump(host):
event = host.service(0)
while event is not None:
handle(host, event)
event = host.service(0)
def handle(host, event):
if event.type == EnetEvent.T_connect:
print(host, "connected to", event.peer.address)
if host is client:
dg = Datagram()
dg.add_string("hello")
dg.add_uint32(42)
event.peer.send_datagram(0, dg)
elif event.type == EnetEvent.T_receive:
dg = event.get_datagram()
it = DatagramIterator(dg)
print(host, "received", it.get_string(), it.get_uint32(),
"on channel", event.channel)
elif event.type == EnetEvent.T_disconnect:
print(host, "lost", event.peer.address)
# In a real program this is a task; here, a loop.
for _ in range(100):
pump(server)
pump(client)
Walking through it:
EnetHost.create_server()binds a UDP port. It returnsNoneif the port cannot be bound, so a server should check and report.peer_countis the number of simultaneous connections it will accept;channel_limitthe number of channels per connection.EnetHost.create_client()makes a host that does not listen. Give it more than one peer slot even if it will only ever hold one connection: a connection that is being closed keeps its slot until the other side acknowledges, and a client with a single slot cannot reconnect until then.EnetHost.connect()starts the handshake and returns theEnetPeerimmediately. The connection exists once both hosts have produced aT_connectevent for it; until thenEnetPeer.connectedisFalse.EnetHost.service()sends what is queued, receives what has arrived, and returns oneEnetEventorNone. Call it until it returnsNoneevery time you service the host; that is what keeps the connection alive.Messages travel as bytes or as a
Datagram(EnetPeer.send_datagram(),EnetEvent.get_datagram()), so the engine’sDatagramIteratorreads them back.
In an application the two pump calls become one task each on the client
and on the server:
def network_task(task):
pump(client)
return task.cont
taskMgr.add(network_task, "network")
Closing a connection is EnetPeer.disconnect(); the other side receives
a T_disconnect event once it has been told. See The Service Loop
for the variants and for what a robust loop looks like.