netcode

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2026 License: BSD-3-Clause Imports: 11 Imported by: 0

README

netcode.go

CI Go Reference codecov

netcode is a secure client/server protocol for multiplayer games built on top of UDP.

This is the official Go implementation: a faithful port of the C reference implementation, written in modern, idiomatic Go. It implements the netcode 1.02 standard and is wire compatible with the C implementation and every other conforming implementation.

Design

Real-time multiplayer games typically use UDP instead of TCP, because head of line blocking delays more recent packets while waiting for older dropped packets to be resent. The problem is that if you want to use UDP, it doesn't provide any concept of connection so you have to build all this yourself, which is a lot of work!

netcode fixes this by providing a minimal and secure connection-oriented protocol on top of UDP, so you can quickly get to exchanging unreliable unordered packets and get busy building the rest of your game network protocol.

Features

  • Secure client connection with connect tokens. Only clients you authorize can connect to your server. This is perfect for a game where you perform matchmaking in a web backend then send clients to connect to a server.
  • Client slot system. Servers have n slots for clients. Client are assigned to a slot when they connect to the server and are quickly denied connection if all slots are taken.
  • Fast clean disconnect on client or server side of connection to quickly open up the slot for a new client, plus timeouts for hard disconnects.
  • Encrypted and signed packets. Packets cannot be tampered with or read by parties not involved in the connection. Cryptography is performed with the same AEAD primitives as the C implementation (ChaCha20-Poly1305 and XChaCha20-Poly1305, via golang.org/x/crypto), so connect tokens and packets interoperate across implementations.
  • Many security features including protection against maliciously crafted packets, packet replay attacks and packet amplification attacks.
  • Support for packet tagging which can significantly reduce jitter on Wi-Fi routers. Read this article for more details.
  • Support for both IPv4 and IPv6 connections.

Usage

go get github.com/mas-bandwidth/netcode.go

Start by generating a random 32 byte private key. Do not share your private key with anybody.

Especially, do not include your private key in your client executable!

Here is a test private key:

var privateKey = [netcode.KeyBytes]byte{
    0x60, 0x6a, 0xbe, 0x6e, 0xc9, 0x19, 0x10, 0xea,
    0x9a, 0x65, 0x62, 0xf6, 0x6f, 0x2b, 0x30, 0xe4,
    0x43, 0x71, 0xd6, 0x2c, 0xd1, 0x99, 0x27, 0x26,
    0x6b, 0x3c, 0x60, 0xf4, 0xb7, 0x15, 0xab, 0xa1,
}

Create a server with the private key:

serverAddress := "127.0.0.1:40000"

serverConfig := &netcode.ServerConfig{
    ProtocolID: protocolID,
    PrivateKey: privateKey,
}

server, err := netcode.NewServer(serverAddress, serverConfig, time)
if err != nil {
    log.Fatalf("error: failed to create server (%v)", err)
}

Then start the server with the number of client slots you want:

server.Start(16)

To connect a client, your client should hit a REST API to your backend that returns a connect token.

There is an example showing how to do this here.

Using a connect token secures your server so that only clients authorized with your backend can connect.

client.Connect(connectToken)

Once the client connects to the server, the client is assigned a client index and can exchange encrypted and signed packets with the server.

Drive both the client and the server by calling Update regularly, for example 60 times per second:

client.Update(time)
server.Update(time)

For more details please see the example programs cmd/client, cmd/server and cmd/client_server, and the API documentation at pkg.go.dev.

Development

go test                                        # run the test suite
go test -race                                  # ...with the race detector
go test -run='^$' -bench=. -benchmem           # benchmarks
go test -fuzz=FuzzReadPacket -fuzztime=60s     # fuzz the packet reader
go run ./cmd/soak                              # soak test, ctrl-C to stop

The fuzz targets (FuzzReadPacket, FuzzWriteReadPacketRoundTrip, FuzzParseAddress, FuzzReadConnectToken, FuzzReadConnectTokenPrivate, FuzzConnectTokenPrivateRoundTrip) are ports of the libFuzzer harnesses in the C implementation. CI runs tests on Linux, macOS and Windows, plus golangci-lint, govulncheck, formatting and go.mod tidiness checks, a short fuzz pass, and a soak run.

Wire compatibility with the C implementation

Wire compatibility is enforced on every pull request, two ways:

  1. Golden wire vectors. testdata/ contains binary vectors — connect tokens, challenge tokens and one packet of every type, encrypted with fixed keys and nonces — generated by the C reference implementation (testdata/generate_vectors.c). The tests in wire_compat_test.go assert this implementation decodes each vector back to the expected fields and re-encodes the same fields to the exact same bytes. These run in every go test.

  2. Live interop. The CI wire-compat job checks out and builds the C implementation from source, regenerates the golden vectors and fails if they differ from the committed ones (catching drift on either side), then runs real handshakes and payload exchange over UDP loopback between this implementation and the C example binaries, in both directions (c_interop_test.go). To run these locally against a built checkout of the C repo:

NETCODE_C_BIN_DIR=$HOME/netcode/build/bin go test -run TestCInterop -v

Notes for users of the C library

The API maps directly onto the C API, with C-style create/destroy pairs replaced by Go constructors and Close:

C Go
netcode_init / netcode_term not needed
netcode_client_create / netcode_client_destroy netcode.NewClient / Client.Close
netcode_server_create / netcode_server_destroy netcode.NewServer / Server.Close
netcode_client_create_error / netcode_server_create_error the error return, e.g. errors.Is(err, netcode.ErrServerBindSocketIPv4Failed)
netcode_generate_connect_token netcode.GenerateConnectToken
netcode_client_receive_packet / netcode_client_free_packet Client.ReceivePacket (no free needed)
netcode_log_level netcode.SetLogLevel

Like the C library, this package is single-threaded by design and is not thread safe: each Client and Server must only be updated from one goroutine at a time. Internally, sockets are read by a goroutine that buffers packets on a channel (the Go equivalent of the C library's non-blocking sockets), but all protocol logic runs on the goroutine that calls Update.

Source Code

This repository holds the implementation of netcode in Go.

Other netcode implementations include:

If you'd like to create your own implementation of netcode, please read the netcode 1.02 standard, and see IMPLEMENTERS.md for findings other implementations should check themselves against.

Author

The author of this library is Glenn Fiedler.

Other open source libraries by the same author include: reliable, serialize, and yojimbo.

If you find this software useful, please consider sponsoring it. Thanks!

License

BSD 3-Clause license.

Documentation

Overview

Package netcode implements the netcode 1.02 protocol: a simple protocol for creating secure client/server connections over UDP.

This is a faithful port of the C reference implementation at https://github.com/mas-bandwidth/netcode and is wire compatible with it. See STANDARD.md for the protocol specification.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Index

Examples

Constants

View Source
const (
	AddressNone = 0
	AddressIPv4 = 1
	AddressIPv6 = 2
)

Address types.

View Source
const (
	VersionFull  = "1.3.5"
	VersionMajor = 1
	VersionMinor = 3
	VersionPatch = 5
)
View Source
const (
	ConnectTokenBytes    = 2048
	KeyBytes             = 32
	MacBytes             = 16
	UserDataBytes        = 256
	MaxServersPerConnect = 32

	MaxClients    = 256
	MaxPacketSize = 1200
)
View Source
const (
	ClientStateConnectTokenExpired        = -6
	ClientStateInvalidConnectToken        = -5
	ClientStateConnectionTimedOut         = -4
	ClientStateConnectionResponseTimedOut = -3
	ClientStateConnectionRequestTimedOut  = -2
	ClientStateConnectionDenied           = -1
	ClientStateDisconnected               = 0
	ClientStateSendingConnectionRequest   = 1
	ClientStateSendingConnectionResponse  = 2
	ClientStateConnected                  = 3
)

Client states. The initial state is ClientStateDisconnected. Negative states are error states. The goal state is ClientStateConnected.

View Source
const (
	DisconnectReasonNone             = 0
	DisconnectReasonTimedOut         = 1
	DisconnectReasonClientDisconnect = 2
	DisconnectReasonServerDisconnect = 3
)

The reason the client in a server slot was last disconnected. Tracked per-client slot: reset to None when the server starts and when a new client connects to the slot, and recorded before the connect/disconnect callback fires, so it can be queried from inside that callback via Server.ClientDisconnectReason.

View Source
const (
	LogLevelNone  = 0
	LogLevelError = 1
	LogLevelInfo  = 2
	LogLevelDebug = 3
)

Log levels.

Variables

View Source
var (
	ErrClientParseAddressFailed     = errors.New("netcode: failed to parse client address")
	ErrClientParseAddress2Failed    = errors.New("netcode: failed to parse client address2")
	ErrClientSimulatorRequiresPort  = errors.New("netcode: must bind to a specific port when using network simulator")
	ErrClientCreateSocketIPv4Failed = errors.New("netcode: failed to create client ipv4 socket")
	ErrClientCreateSocketIPv6Failed = errors.New("netcode: failed to create client ipv6 socket")
)

Client create errors, returned from NewClient and NewClientDual.

View Source
var (
	ErrServerParseAddressFailed     = errors.New("netcode: failed to parse server public address")
	ErrServerParseAddress2Failed    = errors.New("netcode: failed to parse server public address2")
	ErrServerCreateSocketIPv4Failed = errors.New("netcode: failed to create server ipv4 socket")
	ErrServerCreateSocketIPv6Failed = errors.New("netcode: failed to create server ipv6 socket")
	ErrServerBindSocketIPv4Failed   = errors.New("netcode: failed to bind server ipv4 socket")
	ErrServerBindSocketIPv6Failed   = errors.New("netcode: failed to bind server ipv6 socket")
)

Server create errors, returned from NewServer and NewServerDual. Bind failures are reported separately from other socket errors because a port already in use is the common operational failure for dedicated servers.

Functions

func ClientStateName

func ClientStateName(clientState int) string

ClientStateName returns a human readable name for a client state.

func EnablePacketTagging

func EnablePacketTagging()

EnablePacketTagging tags packets sent from sockets created after this call as low latency (DSCP EF) which can significantly reduce jitter on Wi-Fi routers. It is off by default because it doesn't play well with some older home routers.

func GenerateConnectToken

func GenerateConnectToken(publicServerAddresses []string,
	internalServerAddresses []string,
	expireSeconds int,
	timeoutSeconds int,
	clientID uint64,
	protocolID uint64,
	privateKey []byte,
	userData []byte) ([]byte, error)

GenerateConnectToken generates a connect token for a client, exactly as the web backend would. Each entry of publicServerAddresses is the address the client connects to, with the corresponding entry of internalServerAddresses being the address the server sees itself as (often the same). Pass a negative expireSeconds or timeoutSeconds to disable expiry or timeout respectively (dev only). userData is up to 256 bytes of user defined data, and may be nil.

The returned connect token is ConnectTokenBytes (2048 bytes) long.

Example

The web backend generates a connect token for an authenticated client and returns it over HTTPS. Only the backend and the dedicated servers know the private key.

package main

import (
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"log"

	netcode "github.com/mas-bandwidth/netcode.go"
)

func main() {
	var privateKey [netcode.KeyBytes]byte
	if _, err := rand.Read(privateKey[:]); err != nil {
		log.Fatal(err)
	}

	var clientIDBytes [8]byte
	if _, err := rand.Read(clientIDBytes[:]); err != nil {
		log.Fatal(err)
	}
	clientID := binary.LittleEndian.Uint64(clientIDBytes[:])

	serverAddresses := []string{"127.0.0.1:40000"}

	const (
		expireSeconds  = 30 // how long the token stays valid
		timeoutSeconds = 5  // how long before an idle connection times out
		protocolID     = 0x1122334455667788
	)

	connectToken, err := netcode.GenerateConnectToken(
		serverAddresses, // public addresses the client connects to
		serverAddresses, // internal addresses the servers see themselves as
		expireSeconds, timeoutSeconds, clientID, protocolID, privateKey[:],
		nil, // optional user data, up to netcode.UserDataBytes
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("connect token is %d bytes\n", len(connectToken))
}
Output:
connect token is 2048 bytes

func GenerateKey

func GenerateKey() []byte

GenerateKey generates a random 32 byte encryption key.

func RandomBytes

func RandomBytes(data []byte)

RandomBytes fills data with cryptographically secure random bytes.

func SetLogLevel

func SetLogLevel(level int)

SetLogLevel sets the log level. The default is LogLevelNone.

func SetPrintfFunction

func SetPrintfFunction(function func(format string, args ...any))

SetPrintfFunction overrides where log output goes. The default prints to stdout.

Types

type Address

type Address struct {
	Type uint8
	IPv4 [4]byte
	IPv6 [8]uint16
	Port uint16
}

Address is a network address: an IPv4 or IPv6 address plus a port.

IPv4 addresses are stored as four bytes a.b.c.d in IPv4[0..3]. IPv6 addresses are stored as eight 16 bit groups [a:b:c:d:e:f:g:h] in IPv6[0..7], in the order they appear in the address string.

func ParseAddress

func ParseAddress(addressString string) (Address, error)

ParseAddress parses an address string in one of the following forms:

"a.b.c.d"          IPv4 address
"a.b.c.d:port"     IPv4 address and port
"a:b:...:h"        IPv6 address
"[a:b:...:h]"      IPv6 address in brackets
"[a:b:...:h]:port" IPv6 address and port

If a port is omitted, it is assumed to be zero.

func (Address) Equal

func (address Address) Equal(other Address) bool

Equal reports whether two addresses have the same type, address and port. Addresses of type AddressNone are never equal to anything, including each other.

func (Address) String

func (address Address) String() string

String returns the address formatted so that it can be parsed back with ParseAddress. A zero port is omitted.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the client side of a netcode connection.

A client is not safe for concurrent use: call all methods from the same goroutine, and drive it by calling Update regularly (for example, 60 times per second).

func NewClient

func NewClient(address string, config *ClientConfig, time float64) (*Client, error)

NewClient creates a client bound to a single address. Bind to port zero to get an ephemeral port, e.g. "0.0.0.0:0" or "[::]:0".

Example

A client: obtain a connect token from your web backend over HTTPS, then connect and update every frame until connected (or an error state).

package main

import (
	"fmt"
	"log"
	"time"

	netcode "github.com/mas-bandwidth/netcode.go"
)

func main() {
	client, err := netcode.NewClient("0.0.0.0:0", nil, 0.0)
	if err != nil {
		log.Fatalf("failed to create client: %v", err)
	}
	defer client.Close()

	connectToken := requestConnectTokenFromWebBackend()

	client.Connect(connectToken)

	start := time.Now()
	deltaTime := time.Second / 60

	for i := 0; i < 10; i++ { // your game loop
		client.Update(time.Since(start).Seconds())

		if client.State() == netcode.ClientStateConnected {
			client.SendPacket([]byte("hello server"))
		}

		if client.State() <= netcode.ClientStateDisconnected {
			fmt.Printf("client failed to connect: %s\n", netcode.ClientStateName(client.State()))
			break
		}

		time.Sleep(deltaTime)
	}
}

// requestConnectTokenFromWebBackend stands in for hitting a REST API on your
// web backend that authenticates the client and returns a connect token.
func requestConnectTokenFromWebBackend() []byte {
	var privateKey [netcode.KeyBytes]byte
	token, err := netcode.GenerateConnectToken(
		[]string{"127.0.0.1:40000"}, []string{"127.0.0.1:40000"},
		30, 5, 1, 0x1122334455667788, privateKey[:], nil)
	if err != nil {
		log.Fatal(err)
	}
	return token
}

func NewClientDual

func NewClientDual(address1String string, address2String string, config *ClientConfig, time float64) (*Client, error)

NewClientDual creates a client bound to two addresses, one IPv4 and one IPv6, so it can connect to servers over either protocol. Bind to port zero to get an ephemeral port. time is the current time in seconds, from any base you like; pass the same time base to Update.

func (*Client) Close

func (client *Client) Close()

Close disconnects the client (sending disconnect packets to the server if connected) and releases its sockets.

func (*Client) Connect

func (client *Client) Connect(connectTokenData []byte)

Connect takes a connect token generated by GenerateConnectToken (typically obtained from the web backend over HTTPS) and starts connecting to one of the server addresses in it. Progress is made in Update; poll State to see the result.

func (*Client) ConnectLoopback

func (client *Client) ConnectLoopback(clientIndex int, maxClients int)

ConnectLoopback puts the client in loopback mode, connected to a local server in the same process without any packets going over the network. See Server.ConnectLoopbackClient for the server side.

func (*Client) Disconnect

func (client *Client) Disconnect()

Disconnect disconnects the client from the server, sending a number of redundant disconnect packets so the server can free the client slot quickly instead of timing out.

func (*Client) DisconnectLoopback

func (client *Client) DisconnectLoopback()

DisconnectLoopback disconnects a client in loopback mode.

func (*Client) Index

func (client *Client) Index() int

Index returns the client slot index assigned by the server, valid once connected.

func (*Client) Loopback

func (client *Client) Loopback() bool

Loopback reports whether the client is in loopback mode.

func (*Client) MaxClients

func (client *Client) MaxClients() int

MaxClients returns the maximum number of client slots on the server the client is connected to, valid once connected.

func (*Client) NextPacketSequence

func (client *Client) NextPacketSequence() uint64

NextPacketSequence returns the sequence number of the next packet the client will send.

func (*Client) Port

func (client *Client) Port() uint16

Port returns the port the client socket is bound to.

func (*Client) ProcessLoopbackPacket

func (client *Client) ProcessLoopbackPacket(packetData []byte, packetSequence uint64)

ProcessLoopbackPacket delivers a payload packet to a client in loopback mode, as if it had been received from the server.

func (*Client) ProcessPacket

func (client *Client) ProcessPacket(from *Address, packetData []byte)

ProcessPacket processes a raw packet received from the given address, as if it had arrived on the client's socket. This is useful together with ClientConfig.OverrideSendAndReceive to drive the client with your own transport.

func (*Client) ReceivePacket

func (client *Client) ReceivePacket() ([]byte, uint64)

ReceivePacket pops the next payload packet received from the server off the receive queue, returning the payload and the sequence number of the packet it arrived in. Returns nil when no packets remain. Call it in a loop after Update until it returns nil.

func (*Client) SendPacket

func (client *Client) SendPacket(packetData []byte)

SendPacket sends a payload packet to the server. The packet must be between 1 and MaxPacketSize bytes. Packets are unreliable and unordered. Does nothing unless the client is connected.

func (*Client) ServerAddress

func (client *Client) ServerAddress() Address

ServerAddress returns the address of the server the client is connecting or connected to.

func (*Client) State

func (client *Client) State() int

State returns the current client state, one of the ClientState constants.

func (*Client) Update

func (client *Client) Update(time float64)

Update advances the client to the given time: it receives and processes packets, sends outgoing packets, and applies timeouts. Call it regularly, for example 60 times per second.

type ClientConfig

type ClientConfig struct {
	// NetworkSimulator, if set, routes all packets through a network simulator
	// instead of real sockets. The client must then bind to a specific port.
	NetworkSimulator *NetworkSimulator

	// StateChangeCallback, if set, is called whenever the client state changes.
	StateChangeCallback func(previousState int, currentState int)

	// SendLoopbackPacketCallback is called to deliver packets sent by a client
	// in loopback mode. See Client.ConnectLoopback.
	SendLoopbackPacketCallback func(clientIndex int, packetData []byte, packetSequence uint64)

	// OverrideSendAndReceive replaces socket send and receive with the
	// SendPacketOverride and ReceivePacketOverride callbacks. No sockets are
	// created.
	OverrideSendAndReceive bool
	SendPacketOverride     func(to *Address, packetData []byte)
	ReceivePacketOverride  func() (packetData []byte, from Address, ok bool)
}

ClientConfig configures a Client. The zero value gives working defaults: pass nil to NewClient to use it.

type NetworkSimulator

type NetworkSimulator struct {
	LatencyMilliseconds    float32
	JitterMilliseconds     float32
	PacketLossPercent      float32
	DuplicatePacketPercent float32
	// contains filtered or unexported fields
}

NetworkSimulator simulates latency, jitter, packet loss and duplicate packets between clients and servers created with it, entirely in memory. It is used by the test suite and is handy for testing your own protocol under adverse network conditions.

Set the public fields before sending packets. Zero values simulate a perfect network.

func NewNetworkSimulator

func NewNetworkSimulator() *NetworkSimulator

NewNetworkSimulator creates a network simulator.

func (*NetworkSimulator) ReceivePackets

func (sim *NetworkSimulator) ReceivePackets(to *Address, maxPackets int) (packetData [][]byte, from []Address)

ReceivePackets pops up to maxPackets packets addressed to the given address out of the pending receive buffer. It returns the packet payloads and the addresses they were sent from.

func (*NetworkSimulator) Reset

func (sim *NetworkSimulator) Reset()

Reset discards all packets in flight and reseeds the random number generator.

func (*NetworkSimulator) SendPacket

func (sim *NetworkSimulator) SendPacket(from, to *Address, packetData []byte)

SendPacket queues a packet for delivery from one address to another, subject to the simulated latency, jitter, packet loss and duplication.

func (*NetworkSimulator) Update

func (sim *NetworkSimulator) Update(time float64)

Update advances the simulator to the given time, moving any packets whose delivery time has passed into the pending receive buffer. Packets that were not picked up with ReceivePackets since the last update are discarded.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the dedicated server side of the netcode protocol. It manages a set of client slots, where each slot from [0,maxClients-1] represents room for one connected client.

A server is not safe for concurrent use: call all methods from the same goroutine, and drive it by calling Update regularly (for example, 60 times per second).

func NewServer

func NewServer(serverAddressString string, config *ServerConfig, time float64) (*Server, error)

NewServer creates a server with a single public address, e.g. "127.0.0.1:40000". The public address must match an address in the connect tokens clients connect with.

Example

A dedicated server: create it with the private key shared with the web backend, start it with the number of client slots, then update it every frame, exchanging payload packets with connected clients.

package main

import (
	"crypto/rand"
	"log"
	"time"

	netcode "github.com/mas-bandwidth/netcode.go"
)

func main() {
	var privateKey [netcode.KeyBytes]byte
	if _, err := rand.Read(privateKey[:]); err != nil {
		log.Fatal(err)
	}

	config := &netcode.ServerConfig{
		ProtocolID: 0x1122334455667788,
		PrivateKey: privateKey,
	}

	server, err := netcode.NewServer("127.0.0.1:40000", config, 0.0)
	if err != nil {
		log.Fatalf("failed to create server: %v", err)
	}
	defer server.Close()

	server.Start(16)

	start := time.Now()
	deltaTime := time.Second / 60

	for i := 0; i < 10; i++ { // your game loop
		server.Update(time.Since(start).Seconds())

		for clientIndex := 0; clientIndex < server.MaxClients(); clientIndex++ {
			for {
				packet, sequence := server.ReceivePacket(clientIndex)
				if packet == nil {
					break
				}
				_ = sequence // process the payload packet from this client...
			}
		}

		time.Sleep(deltaTime)
	}
}

func NewServerDual

func NewServerDual(serverAddress1String string, serverAddress2String string, config *ServerConfig, time float64) (*Server, error)

NewServerDual creates a server with two public addresses, one IPv4 and one IPv6, so clients can connect over either protocol. time is the current time in seconds, from any base you like; pass the same time base to Update.

func (*Server) ClientAddress

func (server *Server) ClientAddress(clientIndex int) Address

ClientAddress returns the address of the client in the given slot.

func (*Server) ClientConnected

func (server *Server) ClientConnected(clientIndex int) bool

ClientConnected reports whether a client is connected in the given slot.

func (*Server) ClientDisconnectReason

func (server *Server) ClientDisconnectReason(clientIndex int) int

ClientDisconnectReason returns why the client in the given slot was last disconnected: one of the DisconnectReason constants. It is reset to DisconnectReasonNone when the server starts and when a new client connects to the slot, and is recorded before the ConnectDisconnectCallback fires, so it can be queried from inside that callback.

func (*Server) ClientID

func (server *Server) ClientID(clientIndex int) uint64

ClientID returns the client id of the client in the given slot, or zero if no client is connected there.

func (*Server) ClientLoopback

func (server *Server) ClientLoopback(clientIndex int) bool

ClientLoopback reports whether the client in the given slot is in loopback mode.

func (*Server) ClientUserData

func (server *Server) ClientUserData(clientIndex int) []byte

ClientUserData returns the user data from the connect token of the client in the given slot. It is UserDataBytes long.

func (*Server) Close

func (server *Server) Close()

Close stops the server, disconnecting any connected clients, and releases its sockets.

func (*Server) ConnectLoopbackClient

func (server *Server) ConnectLoopbackClient(clientIndex int, clientID uint64, userData []byte)

ConnectLoopbackClient connects a client to the given slot in loopback mode. Packets for this client flow through the SendLoopbackPacketCallback and ProcessLoopbackPacket instead of the network. This is intended for a local player being hosted in the same process as the server, e.g. listen servers.

func (*Server) DisconnectAllClients

func (server *Server) DisconnectAllClients()

DisconnectAllClients disconnects all connected clients. Loopback clients are left alone; use DisconnectLoopbackClient for those.

func (*Server) DisconnectClient

func (server *Server) DisconnectClient(clientIndex int)

DisconnectClient disconnects the client in the given slot, sending a number of redundant disconnect packets so the client finds out quickly instead of timing out.

func (*Server) DisconnectLoopbackClient

func (server *Server) DisconnectLoopbackClient(clientIndex int)

DisconnectLoopbackClient disconnects the loopback client in the given slot.

func (*Server) MaxClients

func (server *Server) MaxClients() int

MaxClients returns the number of client slots the server was started with.

func (*Server) NextPacketSequence

func (server *Server) NextPacketSequence(clientIndex int) uint64

NextPacketSequence returns the sequence number of the next packet the server will send to the given client.

func (*Server) NumConnectedClients

func (server *Server) NumConnectedClients() int

NumConnectedClients returns the number of clients currently connected.

func (*Server) Port

func (server *Server) Port() uint16

Port returns the port the server socket is bound to.

func (*Server) ProcessLoopbackPacket

func (server *Server) ProcessLoopbackPacket(clientIndex int, packetData []byte, packetSequence uint64)

ProcessLoopbackPacket delivers a payload packet from a loopback client to the server, as if it had been received over the network.

func (*Server) ProcessPacket

func (server *Server) ProcessPacket(from *Address, packetData []byte)

ProcessPacket processes a raw packet received from the given address, as if it had arrived on one of the server's sockets. This is useful together with ServerConfig.OverrideSendAndReceive to drive the server with your own transport.

func (*Server) ReceivePacket

func (server *Server) ReceivePacket(clientIndex int) ([]byte, uint64)

ReceivePacket pops the next payload packet received from the client in the given slot, returning the payload and the sequence number of the packet it arrived in. Returns nil when no packets remain. Call it in a loop after Update until it returns nil.

func (*Server) Running

func (server *Server) Running() bool

Running reports whether the server has been started.

func (*Server) SendPacket

func (server *Server) SendPacket(clientIndex int, packetData []byte)

SendPacket sends a payload packet to the client in the given slot. The packet must be between 1 and MaxPacketSize bytes. Packets are unreliable and unordered.

func (*Server) Start

func (server *Server) Start(maxClients int)

Start starts the server with the given number of client slots, in [1,MaxClients]. If the server is already running it is stopped and restarted.

func (*Server) Stop

func (server *Server) Stop()

Stop stops the server, disconnecting all clients. The server can be started again with Start.

func (*Server) Update

func (server *Server) Update(time float64)

Update advances the server to the given time: it receives and processes packets, sends keep-alive packets, and times out clients. Call it regularly, for example 60 times per second.

type ServerConfig

type ServerConfig struct {
	// ProtocolID is a 64 bit value unique to this particular game/application.
	// Only clients with a connect token generated for the same protocol id can
	// connect.
	ProtocolID uint64

	// PrivateKey is shared between the web backend and the dedicated servers.
	// Do not share your private key with anybody, and especially, do not
	// include it in your client executable!
	PrivateKey [KeyBytes]byte

	// NetworkSimulator, if set, routes all packets through a network simulator
	// instead of real sockets.
	NetworkSimulator *NetworkSimulator

	// ConnectDisconnectCallback, if set, is called when a client connects to
	// or disconnects from the server. During a disconnect it fires before the
	// client slot is reset, so the slot can still be queried from inside the
	// callback.
	ConnectDisconnectCallback func(clientIndex int, connected bool)

	// SendLoopbackPacketCallback is called to deliver packets sent to a client
	// in loopback mode. See Server.ConnectLoopbackClient.
	SendLoopbackPacketCallback func(clientIndex int, packetData []byte, packetSequence uint64)

	// OverrideSendAndReceive replaces socket send and receive with the
	// SendPacketOverride and ReceivePacketOverride callbacks. No sockets are
	// created.
	OverrideSendAndReceive bool
	SendPacketOverride     func(to *Address, packetData []byte)
	ReceivePacketOverride  func() (packetData []byte, from Address, ok bool)
}

ServerConfig configures a Server. At minimum set ProtocolID and PrivateKey.

Directories

Path Synopsis
cmd
client command
netcode example client
netcode example client
client_server command
netcode example client/server
netcode example client/server
server command
netcode example server
netcode example server
soak command
netcode soak test
netcode soak test

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL