Skip to the content.

< Previous: Getting Started | 🏠 Home | Next: Advanced Usage >


Basic Usage (Server)

The UdpListener class allows you to create a high-performance UDP receiver that automatically dispatches incoming datagrams to a background worker pool.

Starting the Server

#include "cppudpnet.hpp"
#include <iostream>

int main() {
    // Construct UdpListener. Can bind to IPv4 (e.g., "0.0.0.0"), IPv6 (e.g., "::"), or hostname.
    // Binding to "::" enables dual-stack support by default on supported operating systems.
    cppudpnet::UdpListener server(8080, "0.0.0.0");

    // Set a handler to process incoming datagrams
    server.SetDataHandler([](uint64_t session_id, const cppudpnet::PeerAddress& peer,
                             const std::vector<uint8_t>& data) {
        std::string text(data.begin(), data.end());
        std::cout << "Received from " << peer.ToString() << ": " << text << std::endl;
    });

    try {
        server.Start();
        std::cout << "Server running. Press Enter to stop." << std::endl;
        std::cin.get();
        server.Stop();
    } catch (const std::exception& e) {
        std::cerr << "Failed to start server: " << e.what() << std::endl;
    }

    return 0;
}

Dynamic Port Discovery

If you want the operating system to dynamically assign an available port for you (e.g., to avoid port conflicts), you can bind to port 0. After starting the server, you can discover which port was assigned using GetLocalPort():

cppudpnet::UdpListener server(0, "0.0.0.0");
server.Start();

uint16_t assigned_port = server.GetLocalPort();
std::cout << "Server dynamically bound to port: " << assigned_port << std::endl;

Error Handling

cpp-udpnet splits error handling into two categories: synchronous and asynchronous.

  1. Synchronous Errors: Methods like Start() are called directly by your application. If they fail (e.g., port in use, invalid IP), they will throw a std::system_error or std::runtime_error.
  2. Asynchronous Errors: If a failure occurs in the background polling thread, it is broadcasted over the internal PubSub broker to the "error_events" topic as a cppudpnet::ErrorEvent. Alternatively, you can use server.SetErrorHandler for a direct callback.

Here is an example of subscribing to background error events via the PubSub broker:

auto err_sub = server.GetEventBroker().Subscribe<cppudpnet::ErrorEvent>("error_events");
worker.AddSubscription<cppudpnet::ErrorEvent>(err_sub, [](const cppudpnet::ErrorEvent& event) {
    std::cerr << "Background error [" << event.error_code << "]: " << event.message << std::endl;
});

And here is an example of setting a direct error handler callback on the server:

server.SetErrorHandler([](int error_code, const std::string& message) {
    std::cerr << "Direct callback error [" << error_code << "]: " << message << std::endl;
});

Connection State Events

Since UDP is connectionless, cpp-udpnet provides virtual peer session tracking. When a new peer address is seen for the first time, a Connected event is published. When a peer’s idle timeout expires, a Disconnected event is published.

cpppubsub::Worker worker;
auto sub = server.GetEventBroker().Subscribe<cppudpnet::ConnectionEvent>("state_events");

worker.AddSubscription<cppudpnet::ConnectionEvent>(sub, [&server](const cppudpnet::ConnectionEvent& event) {
    if (event.state == cppudpnet::ConnectionState::Connected) {
        std::cout << "New peer: " << event.peer.ToString() << std::endl;
    } else {
        std::cout << "Peer timed out: " << event.peer.ToString() << std::endl;
    }
});

// Start the worker thread
worker.Start();

Logging

You can configure a global logger callback to capture internal logs from the cpp-udpnet library.

cppudpnet::SetLogger([](cppudpnet::LogSeverity severity, const std::string& className, const std::string& message) {
    std::string sevStr;
    switch (severity) {
        case cppudpnet::LogSeverity::Debug: sevStr = "DEBUG"; break;
        case cppudpnet::LogSeverity::Info:  sevStr = "INFO"; break;
        case cppudpnet::LogSeverity::Warn:  sevStr = "WARN"; break;
        case cppudpnet::LogSeverity::Error: sevStr = "ERROR"; break;
    }
    std::cout << "[" << sevStr << "] " << className << ": " << message << std::endl;
});

Server Configuration

UdpListener provides configuration methods to control socket-level behavior, resource bounds, and thread pooling:

Idle Timeout

Peers that have been inactive (no datagrams received) for longer than the specified duration are considered disconnected.

server.SetIdleTimeout(std::chrono::seconds(60));  // Default: 60s

Maximum Datagram Size

Controls the maximum size of the receive buffer for each recvfrom() call.

server.SetMaxDatagramSize(1500);  // Default: 65507 (max UDP payload)

Socket Buffer Sizes

Configures the kernel socket receive and send buffer sizes.

server.SetRecvBufferSize(262144);  // 256 KB
server.SetSendBufferSize(262144);  // 256 KB

Configuration Profiles (UdpProfile)

Instead of tuning buffer sizes and payload parameters individually, you can apply pre-configured performance profiles using ApplyProfile() or inspect current parameters using GetProfile():

// Apply high-throughput profile
server.ApplyProfile(cppudpnet::UdpProfile::HighThroughput());

// Retrieve active profile structure
cppudpnet::UdpProfile profile = server.GetProfile();
std::cout << "Recv Buffer: " << profile.socket_recv_buffer_size << " bytes\n"
          << "Send Buffer: " << profile.socket_send_buffer_size << " bytes\n"
          << "Max Datagram: " << profile.max_datagram_size << " bytes" << std::endl;

Available Factory Presets:

Broadcast

Enables the SO_BROADCAST socket option to allow sending and receiving broadcast datagrams.

server.SetBroadcast(true);  // Default: false

Worker Pool Sizing

Controls the number of background worker threads. Since the underlying worker pool (cppasyncworker::WorkerPool) uses a fixed-size pool, this sets the exact size of the thread pool.

server.SetWorkerThreads(2);  // Sets thread pool size to 2 (Default: std::thread::hardware_concurrency())

Replying to Peers

The UdpListener can send datagrams back to any peer using their address:

server.SetDataHandler([&server](uint64_t session_id, const cppudpnet::PeerAddress& peer,
                                 const std::vector<uint8_t>& data) {
    std::string text(data.begin(), data.end());
    // Echo back to the sender
    server.Send(peer, "Echo: " + text);
});

You can also send to an arbitrary host:port:

server.Send("192.168.1.100", 9000, "Hello there!");

< Previous: Getting Started 🏠 Home Next: Advanced Usage >