ktu

package
v0.0.0-...-6465c35 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2019 License: Apache-2.0 Imports: 11 Imported by: 0

README

RMNP - Realtime Multiplayer Networking Protocol

RMNP aims to combine all the advantages of TCP and the speed of UDP in order to be fast enough to support modern realtime games like first person shooters. It is basically an extension for UDP.

Features

  • Connections (with timeouts and ping calculation)
  • Error detection
  • Small overhead (max 15 bytes for header)
  • Simple congestion control (avoids flooding nodes between sender/receiver)
  • Optional reliable and ordered packet delivery

How it works

The bad thing about TCP is that once a packet is dropped it stops sending all other packets until the missing one is delivered. This can be a huge problem for games that are time sensitive because it is not uncommon for devices to encounter packet-loss. Therefore RMNP facilitates UDP to guarantee fast delivery without any restrictions. Because UDP is stateless RMNP implements an easy way to handle connection and to distinguish between "connected" clients. Every packet contains a small header mainly containing a CRC32 hash to ensure that all received packets were transmitted correctly.

To guarantee reliability the receiver sends acknowledgment packets back to tell the sender which packets it received. The sender resends each packet until it received an acknowledgment or the maximum timeout is reached. Because of that RMNP is not 100% reliable but it can be assumed that a packet will be delivered unless a client has a packet-loss of about 100% for a couple seconds.

Getting started

Installation
go get github.com/obsilp/rmnp
Basic Server

Example Pong Server

package main

import "github.com/obsilp/rmnp"

func main() {
	server := rmnp.NewServer(":10001")
	server.Start() // non-blocking

	// other code ...
}
Basic Client

Example Ping Client

package main

import "github.com/obsilp/rmnp"

func main() {
	client := rmnp.NewClient("127.0.0.1:10001")
	client.Connect() // non-blocking

	// other code ...
}
Callbacks

Events and received packets can be received by setting callbacks. Look at the respective classes for more information.

Client callbacks | Server callbacks

Send types
  • Unreliable - Fast delivery without any guarantee on arrival or order
  • Unreliable Ordered - Same as unreliable but only the most recent packet is accepted
  • Reliable - Packets are guaranteed to arrive but not in order
  • Reliable Ordered - Packets are guaranteed to arrive in order

Ports

License

This project is licensed under the MIT License - see the LICENSE file for details

Acknowledgments

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// CfgMTU is the maximum byte size of a packet (header included).
	CfgMTU = 1024

	// CfgProtocolID is the identification number send with every rmnp packet to filter out unwanted traffic.
	CfgProtocolID byte = 231

	// CfgParallelListenerCount is the amount of goroutines that will be spawned to listen on incoming requests.
	CfgParallelListenerCount = 1

	// CfgMaxSendReceiveQueueSize is the max size of packets that can be queued up before they are processed.
	CfgMaxSendReceiveQueueSize = 100

	// CfgMaxPacketChainLength is the max length of packets that are chained when waiting for missing sequence.
	CfgMaxPacketChainLength byte = 255
)
View Source
var (
	// CfgSequenceBufferSize is the size of the buffer that store the last received packets in order to ack them.
	// Size should be big enough that packets are at least overridden twice (max_sequence % size > 32 && max_sequence / size >= 2).
	// (max_sequence = highest possible sequence number = max value of sequenceNumber)
	CfgSequenceBufferSize sequenceNumber = 200

	// CfgMaxSkippedPackets is the max amount of that are allowed to be skipped during packet loss (should be less than 32).
	CfgMaxSkippedPackets sequenceNumber = 25

	// CfgUpdateLoopTimeout is the max wait duration for the connection update loop (should be less than other timeout variables).
	CfgUpdateLoopTimeout time.Duration = 10

	// CfgSendRemoveTimeout is the time after which packets that have not being acked yet stop to be resend.
	CfgSendRemoveTimeout int64 = 1600

	// CfgChainSkipTimeout is the time after which a missing packet for a complete sequence is ignored and skipped.
	CfgChainSkipTimeout int64 = 3000

	// CfgAutoPingInterval defines the interval for sending a ping packet.
	CfgAutoPingInterval uint8 = 15
)
View Source
var (
	// CfgTimeoutThreshold is the time after which a connection times out if no packets have being send for the specified amount of time.
	CfgTimeoutThreshold time.Duration = 40000

	// CfgMaxPing is the max ping before a connection times out.
	CfgMaxPing int16 = 150
)
View Source
var (
	// CfgRTTSmoothFactor is the factor used to slowly adjust the RTT.
	CfgRTTSmoothFactor float32 = 0.1

	// CfgCongestionThreshold is the max RTT before the connection enters bad mode.
	CfgCongestionThreshold int64 = 250

	// CfgGoodRTTRewardInterval the time after how many seconds a good connection is rewarded.
	CfgGoodRTTRewardInterval int64 = 10 * 1000

	// CfgBadRTTPunishTimeout the time after how many seconds a bad connection is punished.
	CfgBadRTTPunishTimeout int64 = 10 * 1000

	// CfgMaxCongestionRequiredTime the max time it should take to switch between modes.
	CfgMaxCongestionRequiredTime int64 = 60 * 1000

	// CfgDefaultCongestionRequiredTime the initial time it should take to switch back from bad to good mode.
	CfgDefaultCongestionRequiredTime int64 = 4 * 1000

	// CfgCongestionPacketReduction is the amount of unreliable packets that get dropped in bad mode.
	CfgCongestionPacketReduction uint8 = 4
)
View Source
var (
	// CfgBadModeMultiplier is the multiplier for variables in bad mode.
	CfgBadModeMultiplier float32 = 2.5

	// CfgResendTimeout is the default timeout for packets before resend.
	CfgResendTimeout int64 = 50

	// CfgMaxPacketResends is the default max amount of packets to resend during one update.
	CfgMaxPacketResends int64 = 15

	// CfgReackTimeout is the default timeout before a manual ack packet gets send.
	CfgReackTimeout int64 = 50
)
View Source
var (
	// StatSendBytes (atomic) counts the total amount of bytes send.
	StatSendBytes uint64

	// StatReceivedBytes (atomic) counts the total amount of bytes received.
	// Not the same as StatProcessedBytes because received packets may be discarded.
	StatReceivedBytes uint64

	// StatProcessedBytes (atomic) counts the total size of all processed packets.
	StatProcessedBytes uint64
)
View Source
var (
	// StatRunningGoRoutines (atomic) counts all currently active goroutines spawned by rmnp
	StatRunningGoRoutines uint64

	// StatGoRoutinePanics (atomic) counts the amount of caught goroutine panics
	StatGoRoutinePanics uint64
)
View Source
var (
	// StatConnects (atomic) counts all successful connects
	StatConnects uint64

	// StatDeniedConnects (atomic) counts all denied connection attempts
	StatDeniedConnects uint64

	// StatDisconnects (atomic) counts all disconnects
	StatDisconnects uint64

	// StatTimeouts (atomic) counts all timeouts
	StatTimeouts uint64
)

Functions

This section is empty.

Types

type Channel

type Channel byte

Channel is the method of sending packets

const (
	// ChannelUnreliable is fast delivery without any guarantee on arrival or order
	ChannelUnreliable Channel = iota
	// ChannelUnreliableOrdered is the same as ChannelUnreliable but only the most recent packet is accepted
	ChannelUnreliableOrdered
	// ChannelReliable guarantees packets to arrive but not in order
	ChannelReliable
	// ChannelReliableOrdered guarantees packets to arrive in order (mimics TCP)
	ChannelReliableOrdered
)

type Client

type Client struct {

	// Server is the Connection to the server (nil if not connected).
	Server *Connection

	// ServerConnect is called when a connection to the server was established.
	ServerConnect ConnectionCallback

	// ServerDisconnect is called when the server disconnected the client.
	ServerDisconnect ConnectionCallback

	// ServerTimeout is called when the connection to the server timed out.
	ServerTimeout ConnectionCallback

	// PacketHandler is called when packets arrive to handle the received data.
	PacketHandler PacketCallback
	// contains filtered or unexported fields
}

Client is used to connect to a rmnp server

func NewClient

func NewClient(server *net.UDPAddr) *Client

NewClient creates and returns a new Client instance that will try to connect to the given server address. It does not connect automatically.

func (*Client) Connect

func (c *Client) Connect()

Connect tries to connect to the server specified in the NewClient call. This call is async. On successful connection the Client.ServerConnect callback is invoked. If no connection can be established after CfgTimeoutThreshold milliseconds Client.ServerTimeout is called.

func (*Client) ConnectWithData

func (c *Client) ConnectWithData(data []byte)

ConnectWithData does the same as Connect but also sends custom data to the server that can be validated in the ClientValidation callback or during the ClientConnect callback.

func (*Client) Disconnect

func (c *Client) Disconnect()

Disconnect immediately disconnects from the server. It invokes no callbacks. This call could take some time because it waits for goroutines to exit.

type Connection

type Connection struct {
	Conn     *net.UDPConn
	Addr     *net.UDPAddr
	IsServer bool
	// contains filtered or unexported fields
}

Connection is a udp connection and handles sending of packets

func (*Connection) Del

func (c *Connection) Del(key byte)

Del deletes a stored value from this connection instance. It is thread safe.

func (*Connection) Disconnect

func (c *Connection) Disconnect(packet []byte)

Disconnect disconnects the connection

func (*Connection) Get

func (c *Connection) Get(key byte) (interface{}, bool)

Get retrieves a stored value from this connection instance and returns if it exists. It is thread safe.

func (*Connection) GetFallback

func (c *Connection) GetFallback(key byte, fallback interface{}) interface{}

GetFallback retrieves a stored value from this connection instance. It is thread safe.

func (*Connection) GetPing

func (c *Connection) GetPing() int16

GetPing returns the current ping to this connection's socket

func (*Connection) SendOnChannel

func (c *Connection) SendOnChannel(channel Channel, data []byte)

SendOnChannel sends the data on the given channel using the dedicated send method for each channel

func (*Connection) SendReliable

func (c *Connection) SendReliable(data []byte)

SendReliable send the data and guarantees that the data arrives. Note that packets are not guaranteed to arrive in the order they were sent. This method is not 100% reliable. (Read more in README)

func (*Connection) SendReliableOrdered

func (c *Connection) SendReliableOrdered(data []byte)

SendReliableOrdered is the same as SendReliable but guarantees that packets will be processed in order. This method is not 100% reliable. (Read more in README)

func (*Connection) SendUnreliable

func (c *Connection) SendUnreliable(data []byte)

SendUnreliable sends the data with no guarantee whether it arrives or not. Note that the packets or not guaranteed to arrive in order.

func (*Connection) SendUnreliableOrdered

func (c *Connection) SendUnreliableOrdered(data []byte)

SendUnreliableOrdered is the same as SendUnreliable but guarantees that if packets do not arrive chronologically the receiver only accepts newer packets and discards older ones.

func (*Connection) Set

func (c *Connection) Set(key byte, value interface{})

Set stores a value associated with the given key in this connection instance. It is thread safe.

func (*Connection) TrySet

func (c *Connection) TrySet(key byte, value interface{}) bool

TrySet stores a value associated with the given key in this connection instance if does not exist yet. It returns whether it was able to set the value. It is thread safe.

type ConnectionCallback

type ConnectionCallback func(*Connection, []byte)

ConnectionCallback is the function called when connections change

type PacketCallback

type PacketCallback func(*Connection, []byte, Channel)

PacketCallback is the function called when a packet is received

type ReadFunc

type ReadFunc func(*net.UDPConn, []byte) (int, *net.UDPAddr, bool)

ReadFunc is the function called to write information to a udp connection

type Serializer

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

Serializer reads and writes binary data

func NewSerializer

func NewSerializer() *Serializer

NewSerializer is a new serializer with an empty buffer

func NewSerializerFor

func NewSerializerFor(buffer []byte) *Serializer

NewSerializerFor creates a serializer based on the contents of the buffer

func (*Serializer) Bytes

func (s *Serializer) Bytes() []byte

Bytes is the byte data stored in the serializer

func (*Serializer) Read

func (s *Serializer) Read(data interface{}) error

Read reads binary data from the serializer

func (*Serializer) ReadPanic

func (s *Serializer) ReadPanic(data interface{})

ReadPanic reads from the serializer and panics if no data is read

func (*Serializer) RemainingSize

func (s *Serializer) RemainingSize() int

RemainingSize is the buffer size minus the bytes that have already been read

func (*Serializer) Write

func (s *Serializer) Write(data interface{}) error

Write writes binary data into the serializer

type Server

type Server struct {

	// ClientConnect is invoked when a new client connects.
	ClientConnect ConnectionCallback

	// ClientDisconnect is invoked when a client disconnects.
	ClientDisconnect ConnectionCallback

	// ClientTimeout is called when a client timed out. After that ClientDisconnect will be called.
	ClientTimeout ConnectionCallback

	// ClientValidation is called when a new client connects to either accept or deny the connection attempt.
	ClientValidation ValidationCallback

	// PacketHandler is called when packets arrive to handle the received data.
	PacketHandler PacketCallback
	// contains filtered or unexported fields
}

Server listens for incoming rmnp packets and manages client connections

func NewServer

func NewServer(address *net.UDPAddr) *Server

NewServer creates and returns a new Server instance that will listen on the specified address and port. It does not start automatically.

func (*Server) Start

func (s *Server) Start()

Start starts the server asynchronously. It invokes no callbacks but the server is guaranteed to be running after this call.

func (*Server) Stop

func (s *Server) Stop()

Stop stops the server and disconnects all clients. It invokes no callbacks. This call could take some time because it waits for goroutines to exit.

type ValidationCallback

type ValidationCallback func(*net.UDPAddr, []byte) bool

ValidationCallback is the function called to validate a connnection

type WriteFunc

type WriteFunc func(*net.UDPConn, *net.UDPAddr, []byte)

WriteFunc is the function called to read information from a udp connection

Jump to

Keyboard shortcuts

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