summaryrefslogtreecommitdiffhomepage
path: root/docs/tutorial.dox
blob: 5dbd0c209ae16f048f1b88a8c0b7ddd31a053cdf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
/**
@page Tutorial Tutorial

@ref Initialization

@ref CreateServer

@ref CreateClient

@ref ManageHost

@ref SendingPacket

@ref Disconnecting

@ref Connecting

@section Initialization 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.

@code
#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);
    ...
    ...
    ...
}
@endcode
        
@section CreateServer 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.

@code
    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);
@endcode

@section CreateClient 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.

@code
    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 */,
                57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */,
                14400 / 8 /* 56K modem with 14 Kbps upstream 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);
@endcode

@section ManageHost 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.

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.

@code
    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;
        }
    }
    ...
    ...
    ...
@endcode

@section SendingPacket Sending a packet to an ENet peer            

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.

@code
    /* 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);
@endcode

@section Disconnecting 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.

@code
    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);
    ...
    ...
    ...
@endcode

@section Connecting 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.

@code
    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.");
    }
    ...
    ...
    ...
@endcode
*/