single header C(99) library to implement client-server network code for games

Overview

nbnet

nbnet is a single header C (C99) library to implement client-server network code for games. It is more precisely designed for fast-paced action games.

nbnet is based on this great series of articles by Glenn Fiedler.

nbnet aims to be as easy to use as possible. nbnet's API is friendly and goes straight to the point; it relies on event polling which makes it easy to integrate into a game loop.

Disclaimer: nbnet is in the early stages of its development and is, first and foremost, a learning project of mine as I explore online game development. If you are looking for a professional production-ready library, this is not the one.

You can see nbnet in action in this video.

If you want to discuss the library, you can join the nbnet's discord server.

Features

  • Connection management
  • Sending/Receiving both reliable ordered and unreliable ordered messages
  • Sending/Receiving messages larger than the MTU (using nbnet's message fragmentation)
  • Bit-level serialization (for bandwidth optimization): integers (signed and unsigned), floats, booleans, and byte arrays
  • Network conditions simulation: ping, jitter, packet loss, packet duplication, and out of order packets)
  • Network statistics: ping, bandwidth (upload and download) and packet loss
  • Web (WebRTC) support (powered by emscripten)
  • Encrypted and authenticated packets

Thanks

nbnet encryption and packet authentication would not have been possible without those three open-source libraries:

Made with nbnet

Boomshakalaka

A fun action game that runs into a web browser, by Duncan Stead (@duncanstead86).

See on YouTube.

nbBR

A WIP battle royal game playable in a web browser.

See on YouTube

Llamageddon

An online multiplayer RTS made for the Ludum Dare 49.

https://ldjam.com/events/ludum-dare/49/llamageddon

nb_tanks

A little online tank game prototype.

See on GitHub

Drivers

nbnet does not directly implement any low level "transport" code and rely on drivers.

A driver is a set of function definitions that live outside the nbnet header and provide a transport layer implementation for nbnet used to send and receive packets.

nbnet comes with two ready to use drivers:

  • UDP : work with a single UDP socket, designed for desktop games
  • WebRTC : work with a single unreliable/unordered data channel, designed for web browser games

Portability

nbnet is developed with portability in mind. I tested (and will continue to do so) the library on the following platforms:

  • Windows
  • OSX
  • Linux
  • Web (Chrome/Firefox/Microsoft Edge/Brave)

How to use

In exactly one of your source file do:

#define NBNET_IMPL

#include "nbnet.h"

Provide a driver implementation. For the UDP driver, just add:

#include "net_drivers/udp.h"

after including the nbnet header in the same source file where you defined NBNET_IMPL.

nbnet does not provide any logging capacibilities so you have to provide your own:

#define NBN_LogInfo(...) SomeLoggingFunction(__VA_ARGS__)
#define NBN_LogError(...) SomeLoggingFunction(__VA_ARGS__)
#define NBN_LogDebug(...) SomeLoggingFunction(__VA_ARGS__)
#define NBN_LogTrace(...) SomeLoggingFunction(__VA_ARGS__)

For memory management, nbnet uses malloc, realloc and free. You can redefine it using the following macros:

#define NBN_Allocator malloc
#define NBN_Reallocator realloc
#define NBN_Deallocator free

All set, from here, I suggest you hop into the examples. If you are interested in using the WebRTC driver, read below.

Byte arrays

nbnet comes with a primitive bit-level serialization system; but, if you want to use your own serialization solution, nbnet lets you send and receive raw byte arrays.

See the echo_bytes example.

WebRTC

nbnet lets you implement web browser online games in C without writing any JS code.

To do that, you need to compile your code with emscripten. You can either use the emcc command directly or use CMake, the examples demonstrate how to use both.

The following emscripten options are mandatory and must always be added to your compilation command line or CMake script.

emscripten does not provide a C API for WebRTC, only a JS one. nbnet provides a wrapper around it so you don't have to write any JS code (oof!). All you have to is compile with:

--js-library "net_drivers/webrtc/js/api.js"

The nbnet JS API uses a bunch of asynchronous functions that you need to let emscripten know about:

-s ASYNCIFY

-s ASYNCIFY_IMPORTS="[\"__js_game_client_start\", \"__js_game_client_close\", \"__js_game_server_start\\"]"

nbnet network conditions simulation run in a separate thread so if you want to use it you need to compile with:

-s USE_PTHREADS=1

If you want to run your code in a web browser, you need to provide a shell file:

--shell-file

To learn about shell files: https://emscripten.org/docs/tools_reference/emcc.html

You can also look at the shell.html from the raylib example.

Apart from that, you probably want to add:

-s ALLOW_MEMORY_GROWTH=1 and -s EXIT_RUNTIME=1

For more information: https://emscripten.org/docs/tools_reference/emcc.html

NodeJS

Most of the time, you want your server code to run in a NodeJS server. You can get NodeJS it from here.

Once it's installed, you need to create a package.json file. Check out the echo and raylib examples to see what this file looks like. (For more information: https://docs.npmjs.com/creating-a-package-json-file)

To run your server, you need to install the required NodeJS packages by running:

npm install

from the directory containing your package.json file.

Then to run your server:

node server.js

server.js being the JS file generated by emscripten.

Web browser

Unless your client is a non-graphical application, you want your client code to run in a web browser.

With the correct options emscripten will output an HTML file. From here, all you need to do is run an HTTP server that serves this file and open it in your web browser.

For testing purposes, I recommend using Python SimpleHTTPServer.

Just run:

python -m SimpleHTTPServer 8000

in the directory containing your HTML file; then, open http://localhost:8000 in your web browser and open your client HTML file.

One significant difference with running JS code in a web browser compared to running it in NodeJS is that you cannot use the NodeJS packaging system. nbnet's WebRTC code relies on NodeJS packages, so, for nbnet to run in a web browser we need to "bundle" those packages into something that can be used by a web browser.

I recommend using browserify.

Once installed you can run:

browserify net_drivers/webrtc/js/nbnet.js -o nbnet_bundle.js

and include the generated nbnet_bundle.js script to your HTML shell file:

See the raylib example to see this operation integrated into a CMake script.

Issues
  • Rework game server clients data structure

    Rework game server clients data structure

    At the moment I use a static array on the game server to store client connections. I believe it's not great because:

    • it limits the number of clients that can be connected at the same time
    • in the UDP driver, I do a linear search to find the connection based on the IP address every time a packet is received
    • in the WebRTC driver I use the NBN_GameServer_FindClientById method which also does a linear search by connection ID

    Linear search if far from optimal and it's done every time a packet is received by a driver. I believe a better solution would be to use a hashmap (or another suitable data structure) instead of an array (in nbnet core) and let the drivers compute the hashes themselves as they might have different ways of storing/retrieving connections from this hashmap.

    Here is are the relevant sources:

    NBN_GameServer_FindClientById

    FindClientConnectionByAddress

    enhancement 
    opened by nathhB 2
  • Add a clean disconnection function to the client API

    Add a clean disconnection function to the client API

    There is currently no way to cleanly disconnect from the server on the client side: you can just stop the client and the server will detect the disconnection after a few seconds as packets will no longer be received.

    The idea is to add a function to the client API that attempts to clean disconnection by sending a specific (library reserved) message (reliably) from the client to the server. Upon reception, the server should probably just close the connection.

    On the client side it might be needed to add a "disconnecting" to probably handle the amount of time between sending the disconnection message and actually being disconnected.

    enhancement good first issue 
    opened by nathhB 2
  • Segfault when restarting nbnet

    Segfault when restarting nbnet

    Calling NBN_GameServer_Start or NBN_GameClient_Start after calling NBN_GameServer_Stop and NBN_GameClient_Stop, respectively, causes a segfault when allocating memory for pooling.

    To reproduce the bug, put the calls in a RAII class/struct like so:

    struct GameServer
    {
        GameServer() { NBN_GameServer_Start(PROTOCOL_NAME, PORT, false); }
        ~GameServer() { NBN_GameServer_Stop(); }
    };
    

    Then in the main loop (using raylib):

    // For simplicity's sake, I use GameServer here
    // but should be an interface to switch between GameServer or GameClient
    std::unique_ptr<GameServer> networkState; 
    
    // Other code
    
    while (!window.ShouldClose())
    {
        // Other code
    
        // Toggle the network state using F1
        if ( IsKeyPressed(KEY_F1) )
        {
            if (networkState)
                networkState.reset();
            else
                networkState.reset(new GameServer());
        }
        // Rest of the code
    }
    

    Pressing F1 thrice should give a segfault.

    opened by emer-santos 1
  • `nbnet` logo

    `nbnet` logo

    This issue is just a recommendation. I think nbnet deserves some catchy logo to get more identity and become more popular.

    I can propose something if you want.

    enhancement 
    opened by raysan5 1
  • Firefox browsers crash the game server

    Firefox browsers crash the game server

    When using NBNet's WebRTC driver compiled through emscripten and running inside nodejs, a connecting Firefox client will cause the game server to crash. Unfortunately the server error logs don't provide any clues, nor does the firefox javascript console.

    If I had to guess, it seems most likely to be a protocol issue in the WebRTC handshake.

    bug 
    opened by DunkUK 1
  • C++ support

    C++ support

    This is the minimal changeset needed to get NBNet compiling in C++ (and specificially MSVC). Some features might be affected, such as authentication, since the __attribute lines had to be taken out to get it compiling.

    opened by DunkUK 0
  • Rapid WebRTC connection/disconnection (page refreshes) can cause type errors

    Rapid WebRTC connection/disconnection (page refreshes) can cause type errors

    This is the result when testing rapid page reloads on the Raylib example project: RuntimeError: abort(TypeError: Cannot read property 'error' of undefined) at Error at jsStackTrace (E:\Git\C++\nbnetlatest\examples\raylib\server.js:1:41013) at stackTrace (E:\Git\C++\nbnetlatest\examples\raylib\server.js:1:41189) at process.abort (E:\Git\C++\nbnetlatest\examples\raylib\server.js:1:25525) at process.emit (events.js:314:20) at processPromiseRejections (internal/process/promises.js:209:33) at processTicksAndRejections (internal/process/task_queues.js:98:32) at process.abort (E:\Git\C++\nbnetlatest\examples\raylib\server.js:1:25556) at process.emit (events.js:314:20) at processPromiseRejections (internal/process/promises.js:209:33) at processTicksAndRejections (internal/process/task_queues.js:98:32)

    My guess is that an NBN_Connection is being referenced after being cleared to an undefined value.

    bug 
    opened by DunkUK 0
  • __NBN_Connection more cache friendly

    __NBN_Connection more cache friendly

    Changed bools in __NBN_Connection struct to bit fields, then moved channels closer to endpoint. Since these are closer together, it will help the cache and thus improve performance. This is highlighted in #21

    opened by carterdugan 0
  • Echo & Echo bytes example do not work on windows

    Echo & Echo bytes example do not work on windows

    Those two examples do not work on windows because of the Sleepfunction conflicting with winapi.

    Also, the examples need to be compiled with -lwsock2 so this should be stated in the README.

    bug documentation enhancement 
    opened by nathhB 0
  • NBN_Connection layout is cache unfriendly

    NBN_Connection layout is cache unfriendly

    __NBN_Connection is big enough (a little above 1 MB per connection) that it doesn't fit into the L2 cache of many systems.

    A quick look into a frequently called function like Connection_ReadNextMessageFromStream shows that channels and endpoint are accessed often and immediately after each other, however, their positions in the struct are very far apart. On my Linux 64b system they look like this:

    (gdb) p offsetof(NBN_Connection, channels)
    $1 = (NBN_Channel *(*)[32]) 0x107318
    
    (gdb) p offsetof(NBN_Connection, endpoint)
    $2 = (struct __NBN_Endpoint **) 0x30
    

    More than a MB apart. I believe this is introducing cache misses and impacting performance. The fix is very straightforward: move frequently used members of the struct closer together.

    opened by Phireh 1
  • Use of reserved identifier names invokes undefined behaviour

    Use of reserved identifier names invokes undefined behaviour

    According to https://en.cppreference.com/w/c/language/identifier

    The following identifiers are reserved and may not be declared in a program (doing so invokes undefined behavior): 
    [...]
    2. All external identifiers that begin with an underscore.
    3. All identifiers that begin with an underscore followed by a capital letter or by another underscore (these reserved identifiers allow the library to use numerous behind-the-scenes non-external macros and functions).
    

    Identifiers like those in extern NBN_MemoryManager __mem_manager (violates 2., 3.) or struct __NBN_Connection { ... }; (violates 3.) could cause the compiler to see adjacent code as UB and optimize it in a destructive way.

    enhancement 
    opened by Phireh 0
  • Fix 1 Complexity, 7 Maintainability, 1 Performance issues in multiple files

    Fix 1 Complexity, 7 Maintainability, 1 Performance issues in multiple files

    CodeFactor found multiple issues:

    Complex Code

    'reject' is defined but never used.

    '_' is defined but never used.

    'ev' is defined but never used.

    Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

    'err' is defined but never used.

    'options' is assigned a value but never used.

    enhancement 
    opened by nathhB 0
  • Soak test: Segfault when calling deinit functions

    Soak test: Segfault when calling deinit functions

    On all tested platforms except for OSX, there is a segfault when calling NBN_GameClient_Deinit or NBN_GameServer_Deinit. For now, it was only reproduced with the soak test but I believe it's a library issue.

    bug 
    opened by nathhB 3
Releases(0.4.1)
Owner
Nathan
Nathan
LibVNCServer/LibVNCClient are cross-platform C libraries that allow you to easily implement VNC server or client functionality in your program.

LibVNCServer: A library for easy implementation of a VNC server. Copyright (C) 2001-2003 Johannes E. Schindelin If you already used LibVNCServer, you

null 851 Aug 8, 2022
Header-only C++14 library for getting network addresses associated with network interface without name lookups on Windows, macOS, Linux, and FreeBSD

NetIF Get addresses associated with network interfaces on a system without using name lookups. Header-only, requires C++14. Usage Add the header file

GMLC-TDC 9 Aug 2, 2022
Netif - Header-only C++14 library for getting network addresses associated with network interface without name lookups on Windows, macOS, Linux, and FreeBSD

NetIF Get addresses associated with network interfaces on a system without using name lookups. Header-only, requires C++14. Usage Add the header file

GMLC-TDC 9 Aug 2, 2022
Realtime Client/Server app for Linux allowing joystick (and other HID) data to be transferred over a local network

netstick What is it? Netstick enables HID devices to be remotely connected between a "client" and "server" over a network connection. It allows the ke

null 29 Jul 24, 2022
A virtual network Differential GNSS server-client project using Precise Point Positioning (PPP). Global coverage. Without physical base station construction needed. An open-source virtual base station approach.

Virtual-Network-DGNSS-Project This project is the software implementation for a publicly available, open-source, client/server VN-DGNSS implementation

null 10 May 20, 2022
SimpleSockets is a lightweight set of classes that allow developers to implement IP based network programs.

------------------------------------------------------------------------------------------ * History -------------------------------------------------

DFHack 139 May 29, 2022
A C++ header-only HTTP/HTTPS server and client library

cpp-httplib A C++11 single-file header-only cross platform HTTP/HTTPS library. It's extremely easy to setup. Just include the httplib.h file in your c

null 7.5k Aug 5, 2022
Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services.

Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services. The project is unique among realtime push solutions in that it is designed to address the needs of API creators. Pushpin is transparent to clients and integrates easily into an API stack.

Fanout 3.1k Aug 4, 2022
A modern C++ network library for developing high performance network services in TCP/UDP/HTTP protocols.

evpp Introduction 中文说明 evpp is a modern C++ network library for developing high performance network services using TCP/UDP/HTTP protocols. evpp provid

Qihoo 360 3k Jul 28, 2022
XMap is a fast network scanner designed for performing Internet-wide IPv6 & IPv4 network research scanning.

XMap is reimplemented and improved thoroughly from ZMap and is fully compatible with ZMap, armed with the "5 minutes" probing speed and novel scanning techniques. XMap is capable of scanning the 32-bits address space in under 45 minutes.

idealeer 175 Jul 17, 2022
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.

Welcome! The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design

Microsoft 7k Aug 6, 2022
Event-driven network library for multi-threaded Linux server in C++11

Muduo is a multithreaded C++ network library based on the reactor pattern. http://github.com/chenshuo/muduo Copyright (c) 2010, Shuo Chen. All righ

Shuo Chen 11.7k Aug 2, 2022
A software C library designed to extract data attributes from network packets, server logs, and from structured events in general, in order to make them available for analysis

MMT-DPI A software C library desinged to extract data attributes from network packets, server logs, and from structured events in general, in odrder t

Montimage 3 Apr 14, 2022
A cross-platform network learning demos. Like high-performance http server

Network-Learn A cross-platform network learning demos (toys). And I try not to use 3rd-party libraries. Welcome to try it out and leave your comments.

Ho 229 23 Jul 6, 2022
Brynet - Header Only Cross platform high performance TCP network library using C++ 11.

Brynet Header Only Cross platform high performance TCP network library using C++ 11. Build status Windows : Linux/MacOS : Features Header only Cross p

IronsDu 856 Aug 3, 2022
Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution

CppServer Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and

Ivan Shynkarenka 867 Aug 8, 2022
C++ websocket client/server library

WebSocket++ (0.8.2) WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket Protocol. It allows integrating WebSocket client an

Peter Thorson 5.7k Aug 10, 2022
Ole Christian Eidheim 737 Aug 6, 2022
websocket and http client and server library, coming with ws, a command line swiss army knife utility

Hello world IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use an

Machine Zone, Inc. 329 Aug 8, 2022