ENet Networking Library: The Beginner's Guide (C++)

A reliable UDP networking layer for C++

Why this site exists: Finding good, easy-to-understand documentation for ENet can be incredibly frustrating for beginners. The official docs are sparse, and most tutorials are outdated. I built this page as a simple place to learn how to use ENet specifically with C++. Made it cause the game i was making needed multiplayer features and i couldn't really understand much of the docs

Table of Contents


1. Introduction

ENet is a simple and robust network communication layer on top of UDP (User Datagram Protocol). It provides an interface for reliable, in-order delivery of packets, making it highly suitable for games and real-time applications where standard TCP may introduce unacceptable latency due to head-of-line blocking.

Key Features:

2. Installation

To use ENet, include the main header file in your source code and link against the ENet library.

#include <enet/enet.h>
#include <iostream>

Note: On Linux, link with -lenet. On Windows, link with enet.lib (or enet64.lib), ws2_32.lib, and winmm.lib.

3. Initialization

You must initialize the ENet library before you can use it, and deinitialize it before your program exits.

if (enet_initialize() != 0) {
    std::cerr << "An error occurred while initializing ENet.\n";
    return 1;
}
atexit(enet_deinitialize);

4. Server / Client Hosts

Connections are managed by hosts. A server binds to a specific port, while a client usually lets the OS assign a port.

Server Creation:

ENetAddress address;
ENetHost* server;

// Bind the server to the default localhost and port 1234
address.host = ENET_HOST_ANY;
address.port = 1234;

server = enet_host_create(&address, 
    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 == nullptr) {
    std::cerr << "An error occurred while trying to create an ENet server host.\n";
    exit(1);
}

Client Creation:

ENetHost* client;

client = enet_host_create(nullptr, // 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 == nullptr) {
    std::cerr << "An error occurred while trying to create an ENet client host.\n";
    exit(1);
}

5. Establishing Connection

A client initiates a connection to a server using the enet_host_connect function.

ENetAddress address;
ENetEvent event;
ENetPeer* peer;

// Connect to localhost:1234
enet_address_set_host(&address, "127.0.0.1");
address.port = 1234;

peer = enet_host_connect(client, &address, 2, 0);

if (peer == nullptr) {
    std::cerr << "No available peers for initiating an ENet connection.\n";
    exit(1);
}

// 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) {
    std::cout << "Connection to 127.0.0.1:1234 succeeded.\n";
} else {
    enet_peer_reset(peer);
    std::cout << "Connection to 127.0.0.1:1234 failed.\n";
}

6. Event Polling

ENet operates primarily through an event loop. You process incoming datagrams and events by calling enet_host_service.

ENetEvent event;

// Poll for network events
while (enet_host_service(server, &event, 1000) > 0) {
    switch (event.type) {
        case ENET_EVENT_TYPE_CONNECT:
            std::cout << "A new client connected from " 
                      << std::hex << event.peer->address.host << std::dec 
                      << ":" << event.peer->address.port << "\n";
            break;

        case ENET_EVENT_TYPE_RECEIVE:
            std::cout << "A packet of length " << event.packet->dataLength
                      << " was received on channel " << (int)event.channelID << ".\n";

            // Clean up the packet now that we're done using it.
            enet_packet_destroy(event.packet);
            break;

        case ENET_EVENT_TYPE_DISCONNECT:
            std::cout << "Client disconnected.\n";
            break;

        case ENET_EVENT_TYPE_NONE:
            break;
    }
}

7. Sending Packets

You can send reliable or unreliable packets over specific channels.

// Create a reliable packet
std::string message = "Hello Server!";
ENetPacket* packet = enet_packet_create(message.c_str(), 
                                         message.length() + 1, 
                                         ENET_PACKET_FLAG_RELIABLE);

// Send the packet to the peer over channel 0
enet_peer_send(peer, 0, packet);

// Optionally flush the buffers to send the packet immediately
// enet_host_flush(host);

8. Advanced Control

Bandwidth Limitation: Determine how much bandwidth the ENet host may use.

// limit incoming to 512Kbps and outgoing to 256Kbps
enet_host_bandwidth_limit(server, 512 * 1024, 256 * 1024);

Latency/Ping: ENet automatically measures the round trip time of the connection.

std::cout << "Current ping to peer: " << peer->roundTripTime << " ms\n";

9. Example: Simple Chat App

The following example demonstrates a basic server and client interacting to form a chat room using Modern C++.

Server Code (server.cpp)

#include <enet/enet.h>
#include <iostream>
#include <string>

int main() {
    if (enet_initialize() != 0) return 1;
    
    ENetAddress address;
    address.host = ENET_HOST_ANY;
    address.port = 1234;
    
    ENetHost* server = enet_host_create(&address, 32, 2, 0, 0);
    if (!server) return 1;
    
    std::cout << "Server listening on port 1234...\n";
    
    ENetEvent event;
    while (true) {
        while (enet_host_service(server, &event, 1000) > 0) {
            if (event.type == ENET_EVENT_TYPE_CONNECT) {
                std::cout << "User connected.\n";
            } else if (event.type == ENET_EVENT_TYPE_RECEIVE) {
                std::string msg(reinterpret_cast<char*>(event.packet->data), event.packet->dataLength);
                std::cout << "Received message: " << msg << "\n";
                
                // Broadcast to everyone
                ENetPacket* broadcastPacket = enet_packet_create(
                    event.packet->data, event.packet->dataLength, ENET_PACKET_FLAG_RELIABLE);
                enet_host_broadcast(server, 0, broadcastPacket);
                
                enet_packet_destroy(event.packet);
            } else if (event.type == ENET_EVENT_TYPE_DISCONNECT) {
                std::cout << "User disconnected.\n";
            }
        }
    }
    
    enet_host_destroy(server);
    enet_deinitialize();
    return 0;
}

Client Code (client.cpp)

#include <enet/enet.h>
#include <iostream>
#include <string>
#include <thread>
#include <atomic>

std::atomic<bool> running(true);

void receive_thread(ENetHost* client) {
    ENetEvent event;
    while (running) {
        while (enet_host_service(client, &event, 10) > 0) {
            if (event.type == ENET_EVENT_TYPE_RECEIVE) {
                std::string msg(reinterpret_cast<char*>(event.packet->data), event.packet->dataLength);
                std::cout << "\nIncoming: " << msg << "\n> " << std::flush;
                enet_packet_destroy(event.packet);
            }
        }
    }
}

int main() {
    if (enet_initialize() != 0) return 1;
    
    ENetHost* client = enet_host_create(nullptr, 1, 2, 0, 0);
    
    ENetAddress address;
    enet_address_set_host(&address, "127.0.0.1");
    address.port = 1234;
    
    ENetPeer* peer = enet_host_connect(client, &address, 2, 0);
    
    ENetEvent event;
    if (enet_host_service(client, &event, 5000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
        std::cout << "Connected. Type '/quit' to exit.\n";
    } else {
        std::cout << "Failed to connect.\n";
        return 1;
    }
    
    // Start receiving thread
    std::thread rx(receive_thread, client);

    std::string input;
    while (true) {
        std::cout << "> ";
        std::getline(std::cin, input);
        
        if (input == "/quit") {
            running = false;
            break;
        }
        
        ENetPacket* packet = enet_packet_create(input.c_str(), input.length() + 1, ENET_PACKET_FLAG_RELIABLE);
        enet_peer_send(peer, 0, packet);
    }
    
    rx.join();
    enet_peer_disconnect(peer, 0);
    enet_host_flush(client);
    
    return 0;
}

© ENet Beginners Documentation Project.