ENet: Tutorial

ENet v1.3.18 Reliable UDP networking library

Tutorial

Initialization

Creating an ENet server

Creating an ENet client

Managing an ENet host

Sending a packet to an ENet peer

Disconnecting an ENet peer

Connecting to an ENet host

# Initialization

You should include the file <enet/enet.h> when using ENet. Do not include <enet.h> without the directory prefix, as this may cause file name conflicts on some systems.

Before using ENet, you must call enet_initialize() to initialize the library. Upon program exit, you should call enet_deinitialize() so that the library may clean up any used resources.

#include <enet/enet.h>
int
main (int argc, char ** argv)
{
if (enet_initialize () != 0)
{
fprintf (stderr, "An error occurred while initializing ENet.\n");
return EXIT_FAILURE;
}
atexit (enet_deinitialize);
...
...
...
}
enet.h
ENet public header file.
enet_initialize
int enet_initialize(void)
Initializes ENet globally.
Definition: unix.c:67
enet_deinitialize
void enet_deinitialize(void)
Shuts down ENet globally.
Definition: unix.c:73

# Creating an ENet server

Servers in ENet are constructed with enet_host_create(). You must specify an address on which to receive data and new connections, as well as the maximum allowable numbers of connected peers. You may optionally specify the incoming and outgoing bandwidth of the server in bytes per second so that ENet may try to statically manage bandwidth resources among connected peers in addition to its dynamic throttling algorithm; specifying 0 for these two options will cause ENet to rely entirely upon its dynamic throttling algorithm to manage bandwidth.

When done with a host, the host may be destroyed with enet_host_destroy(). All connected peers to the host will be reset, and the resources used by the host will be freed.

ENetAddress address;
ENetHost * server;
/* Bind the server to the default localhost. */
/* A specific host address can be specified by */
/* enet_address_set_host (& address, "x.x.x.x"); */
address.host = ENET_HOST_ANY;
/* Bind the server to port 1234. */
address.port = 1234;
server = enet_host_create (& address /* the address to bind the server host to */,
32 /* allow up to 32 clients and/or outgoing connections */,
2 /* allow up to 2 channels to be used, 0 and 1 */,
0 /* assume any amount of incoming bandwidth */,
0 /* assume any amount of outgoing bandwidth */);
if (server == NULL)
{
fprintf (stderr,
"An error occurred while trying to create an ENet server host.\n");
exit (EXIT_FAILURE);
}
...
...
...
enet_host_destroy(server);
ENET_HOST_ANY
#define ENET_HOST_ANY
Definition: enet.h:76
enet_host_create
ENetHost * enet_host_create(const ENetAddress *address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
Creates a host for communicating to peers.
Definition: host.c:29
ENetAddress
Portable internet address structure.
Definition: enet.h:91
ENetAddress::host
enet_uint32 host
Definition: enet.h:92
ENetAddress::port
enet_uint16 port
Definition: enet.h:93
ENetHost
An ENet host for communicating with peers.
Definition: enet.h:366

# Creating an ENet client

Clients in ENet are similarly constructed with enet_host_create() when no address is specified to bind the host to. Bandwidth may be specified for the client host as in the above example. The peer count controls the maximum number of connections to other server hosts that may be simultaneously open.

ENetHost * client;
client = enet_host_create (NULL /* create a client host */,
1 /* only allow 1 outgoing connection */,
2 /* allow up 2 channels to be used, 0 and 1 */,
0 /* assume any amount of incoming bandwidth */,
0 /* assume any amount of outgoing bandwidth */);
if (client == NULL)
{
fprintf (stderr,
"An error occurred while trying to create an ENet client host.\n");
exit (EXIT_FAILURE);
}
...
...
...
enet_host_destroy(client);

# Managing an ENet host

ENet uses a polled event model to notify the programmer of significant events. ENet hosts are polled for events with enet_host_service(), where an optional timeout value in milliseconds may be specified to control how long ENet will poll; if a timeout of 0 is specified, enet_host_service() will return immediately if there are no events to dispatch. enet_host_service() will return 1 if an event was dispatched within the specified timeout.

Beware that most processing of the network with the ENet stack is done inside enet_host_service(). Both hosts that make up the sides of a connection must regularly call this function to ensure packets are actually sent and received. A common symptom of not actively calling enet_host_service() on both ends is that one side receives events while the other does not. The best way to schedule this activity to ensure adequate service is, for example, to call enet_host_service() with a 0 timeout (meaning non-blocking) at the beginning of every frame in a game loop.

Currently there are only four types of significant events in ENet:

An event of type ENET_EVENT_TYPE_NONE is returned if no event occurred within the specified time limit. enet_host_service() will return 0 with this event.

An event of type ENET_EVENT_TYPE_CONNECT is returned when either a new client host has connected to the server host or when an attempt to establish a connection with a foreign host has succeeded. Only the "peer" field of the event structure is valid for this event and contains the newly connected peer.

An event of type ENET_EVENT_TYPE_RECEIVE is returned when a packet is received from a connected peer. The "peer" field contains the peer the packet was received from, "channelID" is the channel on which the packet was sent, and "packet" is the packet that was sent. The packet contained in the "packet" field must be destroyed with enet_packet_destroy() when you are done inspecting its contents.

An event of type ENET_EVENT_TYPE_DISCONNECT is returned when a connected peer has either explicitly disconnected or timed out. Only the "peer" field of the event structure is valid for this event and contains the peer that disconnected. Only the "data" field of the peer is still valid on a disconnect event and must be explicitly reset.

ENetEvent event;
/* Wait up to 1000 milliseconds for an event. */
while (enet_host_service (client, & event, 1000) > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf ("A new client connected from %x:%u.\n",
event.peer -> address.host,
event.peer -> address.port);
/* Store any relevant client information here. */
event.peer -> data = "Client information";
break;
case ENET_EVENT_TYPE_RECEIVE:
printf ("A packet of length %u containing %s was received from %s on channel %u.\n",
event.packet -> dataLength,
event.packet -> data,
event.peer -> data,
event.channelID);
/* Clean up the packet now that we're done using it. */
enet_packet_destroy (event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
printf ("%s disconnected.\n", event.peer -> data);
/* Reset the peer's client information. */
event.peer -> data = NULL;
}
}
...
...
...
ENET_EVENT_TYPE_DISCONNECT
@ ENET_EVENT_TYPE_DISCONNECT
a peer has disconnected.
Definition: enet.h:425
ENET_EVENT_TYPE_RECEIVE
@ ENET_EVENT_TYPE_RECEIVE
a packet has been received from a peer.
Definition: enet.h:433
ENET_EVENT_TYPE_CONNECT
@ ENET_EVENT_TYPE_CONNECT
a connection request initiated by enet_host_connect has completed.
Definition: enet.h:416
enet_packet_destroy
void enet_packet_destroy(ENetPacket *)
Destroys the packet and deallocates its data.
Definition: packet.c:57
enet_host_service
int enet_host_service(ENetHost *, ENetEvent *, enet_uint32)
Waits for events on the host specified and shuttles packets between the host and its peers.
Definition: protocol.c:1794
ENetEvent
An ENet event as returned by enet_host_service().
Definition: enet.h:442
ENetEvent::peer
ENetPeer * peer
peer that generated a connect, disconnect or receive event
Definition: enet.h:444
ENetEvent::packet
ENetPacket * packet
packet associated with the event, if appropriate
Definition: enet.h:447
ENetEvent::channelID
enet_uint8 channelID
channel on the peer that generated the event, if appropriate
Definition: enet.h:445
ENetEvent::type
ENetEventType type
type of the event
Definition: enet.h:443

# Sending a packet to an ENet peer <br>

Packets in ENet are created with enet_packet_create(), where the size of the packet must be specified. Optionally, initial data may be specified to copy into the packet.

Certain flags may also be supplied to enet_packet_create() to control various packet features:

ENET_PACKET_FLAG_RELIABLE specifies that the packet must use reliable delivery. A reliable packet is guaranteed to be delivered, and a number of retry attempts will be made until an acknowledgement is received from the foreign host the packet is sent to. If a certain number of retry attempts is reached without any acknowledgement, ENet will assume the peer has disconnected and forcefully reset the connection. If this flag is not specified, the packet is assumed an unreliable packet, and no retry attempts will be made nor acknowledgements generated.

A packet may be resized (extended or truncated) with enet_packet_resize().

A packet is sent to a foreign host with enet_peer_send(). enet_peer_send() accepts a channel id over which to send the packet to a given peer. Once the packet is handed over to ENet with enet_peer_send(), ENet will handle its deallocation and enet_packet_destroy() should not be used upon it.

One may also use enet_host_broadcast() to send a packet to all connected peers on a given host over a specified channel id, as with enet_peer_send().

Queued packets will be sent on a call to enet_host_service(). Alternatively, enet_host_flush() will send out queued packets without dispatching any events.

/* Create a reliable packet of size 7 containing "packet\0" */
ENetPacket * packet = enet_packet_create ("packet",
strlen ("packet") + 1,
ENET_PACKET_FLAG_RELIABLE);
/* Extend the packet so and append the string "foo", so it now */
/* contains "packetfoo\0" */
enet_packet_resize (packet, strlen ("packetfoo") + 1);
strcpy (& packet -> data [strlen ("packet")], "foo");
/* Send the packet to the peer over channel id 0. */
/* One could also broadcast the packet by */
/* enet_host_broadcast (host, 0, packet); */
enet_peer_send (peer, 0, packet);
...
...
...
/* One could just use enet_host_service() instead. */
enet_host_flush (host);
ENET_PACKET_FLAG_RELIABLE
@ ENET_PACKET_FLAG_RELIABLE
packet must be received by the target peer and resend attempts should be made until the packet is del...
Definition: enet.h:109
enet_packet_resize
int enet_packet_resize(ENetPacket *, size_t)
Attempts to resize the data in the packet to length specified in the dataLength parameter.
Definition: packet.c:77
enet_packet_create
ENetPacket * enet_packet_create(const void *, size_t, enet_uint32)
Creates a packet that may be sent to a peer.
Definition: packet.c:20
enet_peer_send
int enet_peer_send(ENetPeer *, enet_uint8, ENetPacket *)
Queues a packet to be sent.
Definition: peer.c:107
ENetPacket
ENet packet structure.
Definition: enet.h:150

# Disconnecting an ENet peer

Peers may be gently disconnected with enet_peer_disconnect(). A disconnect request will be sent to the foreign host, and ENet will wait for an acknowledgement from the foreign host before finally disconnecting. An event of type ENET_EVENT_TYPE_DISCONNECT will be generated once the disconnection succeeds. Normally timeouts apply to the disconnect acknowledgement, and so if no acknowledgement is received after a length of time the peer will be forcefully disconnected.

enet_peer_reset() will forcefully disconnect a peer. The foreign host will get no notification of a disconnect and will time out on the foreign host. No event is generated.

ENetEvent event;
enet_peer_disconnect (peer, 0);
/* Allow up to 3 seconds for the disconnect to succeed
* and drop any packets received packets.
*/
while (enet_host_service (client, & event, 3000) > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_RECEIVE:
enet_packet_destroy (event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
puts ("Disconnection succeeded.");
return;
...
...
...
}
}
/* We've arrived here, so the disconnect attempt didn't */
/* succeed yet. Force the connection down. */
enet_peer_reset (peer);
...
...
...
enet_peer_disconnect
void enet_peer_disconnect(ENetPeer *, enet_uint32)
Request a disconnection from a peer.
Definition: peer.c:538
enet_peer_reset
void enet_peer_reset(ENetPeer *)
Forcefully disconnects a peer.
Definition: peer.c:382

# Connecting to an ENet host

A connection to a foreign host is initiated with enet_host_connect(). It accepts the address of a foreign host to connect to, and the number of channels that should be allocated for communication. If N channels are allocated for use, their channel ids will be numbered 0 through N-1. A peer representing the connection attempt is returned, or NULL if there were no available peers over which to initiate the connection. When the connection attempt succeeds, an event of type ENET_EVENT_TYPE_CONNECT will be generated. If the connection attempt times out or otherwise fails, an event of type ENET_EVENT_TYPE_DISCONNECT will be generated.

ENetAddress address;
ENetEvent event;
ENetPeer *peer;
/* Connect to some.server.net:1234. */
enet_address_set_host (& address, "some.server.net");
address.port = 1234;
/* Initiate the connection, allocating the two channels 0 and 1. */
peer = enet_host_connect (client, & address, 2, 0);
if (peer == NULL)
{
fprintf (stderr,
"No available peers for initiating an ENet connection.\n");
exit (EXIT_FAILURE);
}
/* Wait up to 5 seconds for the connection attempt to succeed. */
if (enet_host_service (client, & event, 5000) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT)
{
puts ("Connection to some.server.net:1234 succeeded.");
...
...
...
}
else
{
/* Either the 5 seconds are up or a disconnect event was */
/* received. Reset the peer in the event the 5 seconds */
/* had run out without any significant event. */
enet_peer_reset (peer);
puts ("Connection to some.server.net:1234 failed.");
}
...
...
...
enet_address_set_host
int enet_address_set_host(ENetAddress *address, const char *hostName)
Attempts to resolve the host named by the parameter hostName and sets the host field in the address p...
Definition: unix.c:117
enet_host_connect
ENetPeer * enet_host_connect(ENetHost *host, const ENetAddress *address, size_t channelCount, enet_uint32 data)
Initiates a connection to a foreign host.
Definition: host.c:184
ENetPeer
An ENet peer which data packets may be sent or received from.
Definition: enet.h:266