gnet

package module
Version: v1.5.3 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2021 License: MIT Imports: 24 Imported by: 50

README

gnet

English | 🇨🇳中文

📖 Introduction

gnet is an event-driven networking framework that is fast and lightweight. It makes direct epoll and kqueue syscalls rather than using the standard Go net package and works in a similar manner as netty and libuv, which makes gnet achieve a much higher performance than Go net.

gnet is not designed to displace the standard Go net package, but to create a networking server framework for Go that performs on par with Redis and Haproxy for networking packets handling.

gnet sells itself as a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go which works on transport layer with TCP/UDP protocols and Unix Domain Socket , so it allows developers to implement their own protocols(HTTP, RPC, WebSocket, Redis, etc.) of application layer upon gnet for building diversified network applications, for instance, you get an HTTP Server or Web Framework if you implement HTTP protocol upon gnet while you have a Redis Server done with the implementation of Redis protocol upon gnet and so on.

gnet derives from the project: evio while having a much higher performance and more features.

🚀 Features

  • High-performance event-loop under networking model of multiple threads/goroutines
  • Built-in goroutine pool powered by the library ants
  • Built-in memory pool with bytes powered by the library bytebufferpool
  • Lock-free during the entire runtime
  • Concise and easy-to-use APIs
  • Efficient, reusable and scalable memory buffer: Ring-Buffer
  • Supporting multiple protocols/IPC mechanism: TCP, UDP and Unix Domain Socket
  • Supporting multiple load-balancing algorithms: Round-Robin, Source-Addr-Hash and Least-Connections
  • Supporting two event-driven mechanisms: epoll on Linux and kqueue on FreeBSD/DragonFly/Darwin
  • Supporting asynchronous write operation
  • Flexible ticker event
  • SO_REUSEPORT socket option
  • Built-in multiple codecs to encode/decode network frames into/from TCP stream: LineBasedFrameCodec, DelimiterBasedFrameCodec, FixedLengthFrameCodec and LengthFieldBasedFrameCodec, referencing netty codec, also supporting customized codecs
  • Supporting Windows platform with event-driven mechanism of IOCP Go stdlib: net
  • Implementation of gnet Client

📊 Performance

Benchmarks on TechEmpower

# Hardware Environment
CPU: 28 HT Cores Intel(R) Xeon(R) Gold 5120 CPU @ 2.20GHz
Mem: 32GB RAM
OS : Ubuntu 18.04.3 4.15.0-88-generic #88-Ubuntu
Net: Switched 10-gigabit ethernet
Go : go1.14.x linux/amd64

All language

This is the top 50 on the framework ranking of all programming languages consists of a total of 422 frameworks from all over the world where gnet is the runner-up.

Golang

This is the full framework ranking of Go and gnet tops all the other frameworks, which makes gnet the fastest networking framework in Go.

To see the full ranking list, visit TechEmpower Plaintext Benchmark.

Contrasts to the similar networking libraries

On Linux (epoll)

Test Environment
# Machine information
        OS : Ubuntu 20.04/x86_64
       CPU : 8 processors, AMD EPYC 7K62 48-Core Processor
    Memory : 16.0 GiB

# Go version and settings
Go Version : go1.15.7 linux/amd64
GOMAXPROCS : 8

# Netwokr settings
TCP connections : 300
Test duration   : 30s
Echo Server

HTTP Server

On FreeBSD (kqueue)

Test Environment
# Machine information
        OS : macOS Catalina 10.15.7/x86_64
       CPU : 6-Core Intel Core i7
    Memory : 16.0 GiB

# Go version and configurations
Go Version : go1.15.7 darwin/amd64
GOMAXPROCS : 12

# Netwokr settings
TCP connections : 100
Test duration   : 20s
Echo Server

HTTP Server

🏛 Website

Please visit the official website for more details about architecture, usage and other information of gnet.

⚠️ License

Source code in gnet is available under the MIT License.

👏 Contributors

Please read the Contributing Guidelines before opening a PR and thank you to all the developers who already made contributions to gnet!

⚓ Relevant Articles

🎡 User cases

The following companies/organizations use gnet as the underlying network service in production.

          

If you have gnet integrated into projects, feel free to open a pull request refreshing this list of user cases.

💰 Backers

Support us with a monthly donation and help us continue our activities.

💎 Sponsors

Become a bronze sponsor with a monthly donation of $10 and get your logo on our README on Github.

☕️ Buy me a coffee

Please be sure to leave your name, Github account or other social media accounts when you donate by the following means so that I can add it to the list of donors as a token of my appreciation.

        

💴 Donors

Patrick Othmer Jimmy ChenZhen Mai Yang 王开帅 Unger Alejandro Swaggadan

💵 Paid Support

If you need a tailored version of gnet and want the author to help develop it, or bug fix/fast resolution/consultation which takes a lot of effort, you can request paid support here.

🔑 JetBrains OS licenses

gnet had been being developed with GoLand IDE under the free JetBrains Open Source license(s) granted by JetBrains s.r.o., hence I would like to express my thanks here.

🔋 Sponsorship

This project is supported by:

Documentation

Index

Constants

This section is empty.

Variables

View Source
var CRLFByte = byte('\n')

CRLFByte represents a byte of CRLF.

Functions

func Serve

func Serve(eventHandler EventHandler, protoAddr string, opts ...Option) (err error)

Serve starts handling events for the specified address.

Address should use a scheme prefix and be formatted like `tcp://192.168.0.10:9851` or `unix://socket`. Valid network schemes:

tcp   - bind to both IPv4 and IPv6
tcp4  - IPv4
tcp6  - IPv6
udp   - bind to both IPv4 and IPv6
udp4  - IPv4
udp6  - IPv6
unix  - Unix Domain Socket

The "tcp" network scheme is assumed when one is not specified.

func Stop added in v1.3.2

func Stop(ctx context.Context, protoAddr string) error

Stop gracefully shuts down the server without interrupting any active event-loops, it waits indefinitely for connections and event-loops to be closed and then shuts down.

Types

type Action

type Action int

Action is an action that occurs after the completion of an event.

const (
	// None indicates that no action should occur following an event.
	None Action = iota

	// Close closes the connection.
	Close

	// Shutdown shutdowns the server.
	Shutdown
)

type BuiltInFrameCodec added in v1.0.0

type BuiltInFrameCodec struct{}

BuiltInFrameCodec is the built-in codec which will be assigned to gnet server when customized codec is not set up.

func (*BuiltInFrameCodec) Decode added in v1.0.0

func (cc *BuiltInFrameCodec) Decode(c Conn) ([]byte, error)

Decode ...

func (*BuiltInFrameCodec) Encode added in v1.0.0

func (cc *BuiltInFrameCodec) Encode(c Conn, buf []byte) ([]byte, error)

Encode ...

type Conn

type Conn interface {
	// Context returns a user-defined context.
	Context() (ctx interface{})

	// SetContext sets a user-defined context.
	SetContext(ctx interface{})

	// LocalAddr is the connection's local socket address.
	LocalAddr() (addr net.Addr)

	// RemoteAddr is the connection's remote peer address.
	RemoteAddr() (addr net.Addr)

	// Read reads all data from inbound ring-buffer and event-loop-buffer without moving "read" pointer, which means
	// it does not evict the data from buffers actually and those data will present in buffers until the
	// ResetBuffer method is called.
	Read() (buf []byte)

	// ResetBuffer resets the buffers, which means all data in inbound ring-buffer and event-loop-buffer will be evicted.
	ResetBuffer()

	// ReadN reads bytes with the given length from inbound ring-buffer and event-loop-buffer without moving
	// "read" pointer, which means it will not evict the data from buffers until the ShiftN method is called,
	// it reads data from the inbound ring-buffer and event-loop-buffer and returns both bytes and the size of it.
	// If the length of the available data is less than the given "n", ReadN will return all available data, so you
	// should make use of the variable "size" returned by it to be aware of the exact length of the returned data.
	ReadN(n int) (size int, buf []byte)

	// ShiftN shifts "read" pointer in the internal buffers with the given length.
	ShiftN(n int) (size int)

	// BufferLength returns the length of available data in the internal buffers.
	BufferLength() (size int)

	// SendTo writes data for UDP sockets, it allows you to send data back to UDP socket in individual goroutines.
	SendTo(buf []byte) error

	// AsyncWrite writes data to client/connection asynchronously, usually you would call it in individual goroutines
	// instead of the event-loop goroutines.
	AsyncWrite(buf []byte) error

	// Wake triggers a React event for this connection.
	Wake() error

	// Close closes the current connection.
	Close() error
}

Conn is a interface of gnet connection.

type DecoderConfig added in v1.0.0

type DecoderConfig struct {
	// ByteOrder is the ByteOrder of the length field.
	ByteOrder binary.ByteOrder
	// LengthFieldOffset is the offset of the length field
	LengthFieldOffset int
	// LengthFieldLength is the length of the length field
	LengthFieldLength int
	// LengthAdjustment is the compensation value to add to the value of the length field
	LengthAdjustment int
	// InitialBytesToStrip is the number of first bytes to strip out from the decoded frame
	InitialBytesToStrip int
}

DecoderConfig config for decoder.

type DelimiterBasedFrameCodec added in v1.0.0

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

DelimiterBasedFrameCodec encodes/decodes specific-delimiter-separated frames into/from TCP stream.

func NewDelimiterBasedFrameCodec added in v1.0.0

func NewDelimiterBasedFrameCodec(delimiter byte) *DelimiterBasedFrameCodec

NewDelimiterBasedFrameCodec instantiates and returns a codec with a specific delimiter.

func (*DelimiterBasedFrameCodec) Decode added in v1.0.0

func (cc *DelimiterBasedFrameCodec) Decode(c Conn) ([]byte, error)

Decode ...

func (*DelimiterBasedFrameCodec) Encode added in v1.0.0

func (cc *DelimiterBasedFrameCodec) Encode(c Conn, buf []byte) ([]byte, error)

Encode ...

type EncoderConfig added in v1.0.0

type EncoderConfig struct {
	// ByteOrder is the ByteOrder of the length field.
	ByteOrder binary.ByteOrder
	// LengthFieldLength is the length of the length field.
	LengthFieldLength int
	// LengthAdjustment is the compensation value to add to the value of the length field
	LengthAdjustment int
	// LengthIncludesLengthFieldLength is true, the length of the prepended length field is added to the value of
	// the prepended length field
	LengthIncludesLengthFieldLength bool
}

EncoderConfig config for encoder.

type EventHandler added in v1.0.0

type EventHandler interface {
	// OnInitComplete fires when the server is ready for accepting connections.
	// The parameter:server has information and various utilities.
	OnInitComplete(server Server) (action Action)

	// OnShutdown fires when the server is being shut down, it is called right after
	// all event-loops and connections are closed.
	OnShutdown(server Server)

	// OnOpened fires when a new connection has been opened.
	// The parameter:c has information about the connection such as it's local and remote address.
	// Parameter:out is the return value which is going to be sent back to the client.
	// It is generally not recommended to send large amounts of data back to the client in OnOpened.
	//
	// Note that the bytes returned by OnOpened will be sent back to client without being encoded.
	OnOpened(c Conn) (out []byte, action Action)

	// OnClosed fires when a connection has been closed.
	// The parameter:err is the last known connection error.
	OnClosed(c Conn, err error) (action Action)

	// PreWrite fires just before any data is written to any client socket, this event function is usually used to
	// put some code of logging/counting/reporting or any prepositive operations before writing data to client.
	PreWrite()

	// React fires when a connection sends the server data.
	// Call c.Read() or c.ReadN(n) within the parameter:c to read incoming data from client.
	// Parameter:out is the return value which is going to be sent back to the client.
	React(frame []byte, c Conn) (out []byte, action Action)

	// Tick fires immediately after the server starts and will fire again
	// following the duration specified by the delay return value.
	Tick() (delay time.Duration, action Action)
}

EventHandler represents the server events' callbacks for the Serve call. Each event has an Action return value that is used manage the state of the connection and server.

type EventServer added in v1.0.0

type EventServer struct{}

EventServer is a built-in implementation of EventHandler which sets up each method with a default implementation, you can compose it with your own implementation of EventHandler when you don't want to implement all methods in EventHandler.

func (*EventServer) OnClosed added in v1.0.0

func (es *EventServer) OnClosed(c Conn, err error) (action Action)

OnClosed fires when a connection has been closed. The parameter:err is the last known connection error.

func (*EventServer) OnInitComplete added in v1.0.0

func (es *EventServer) OnInitComplete(svr Server) (action Action)

OnInitComplete fires when the server is ready for accepting connections. The parameter:server has information and various utilities.

func (*EventServer) OnOpened added in v1.0.0

func (es *EventServer) OnOpened(c Conn) (out []byte, action Action)

OnOpened fires when a new connection has been opened. The parameter:c has information about the connection such as it's local and remote address. Parameter:out is the return value which is going to be sent back to the client.

func (*EventServer) OnShutdown added in v1.2.0

func (es *EventServer) OnShutdown(svr Server)

OnShutdown fires when the server is being shut down, it is called right after all event-loops and connections are closed.

func (*EventServer) PreWrite added in v1.0.0

func (es *EventServer) PreWrite()

PreWrite fires just before any data is written to any client socket, this event function is usually used to put some code of logging/counting/reporting or any prepositive operations before writing data to client.

func (*EventServer) React added in v1.0.0

func (es *EventServer) React(frame []byte, c Conn) (out []byte, action Action)

React fires when a connection sends the server data. Call c.Read() or c.ReadN(n) within the parameter:c to read incoming data from client. Parameter:out is the return value which is going to be sent back to the client.

func (*EventServer) Tick added in v1.0.0

func (es *EventServer) Tick() (delay time.Duration, action Action)

Tick fires immediately after the server starts and will fire again following the duration specified by the delay return value.

type FixedLengthFrameCodec added in v1.0.0

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

FixedLengthFrameCodec encodes/decodes fixed-length-separated frames into/from TCP stream.

func NewFixedLengthFrameCodec added in v1.0.0

func NewFixedLengthFrameCodec(frameLength int) *FixedLengthFrameCodec

NewFixedLengthFrameCodec instantiates and returns a codec with fixed length.

func (*FixedLengthFrameCodec) Decode added in v1.0.0

func (cc *FixedLengthFrameCodec) Decode(c Conn) ([]byte, error)

Decode ...

func (*FixedLengthFrameCodec) Encode added in v1.0.0

func (cc *FixedLengthFrameCodec) Encode(c Conn, buf []byte) ([]byte, error)

Encode ...

type ICodec added in v1.0.0

type ICodec interface {
	// Encode encodes frames upon server responses into TCP stream.
	Encode(c Conn, buf []byte) ([]byte, error)
	// Decode decodes frames from TCP stream via specific implementation.
	Decode(c Conn) ([]byte, error)
}

ICodec is the interface of gnet codec.

type LengthFieldBasedFrameCodec added in v1.0.0

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

LengthFieldBasedFrameCodec is the refactoring from https://github.com/smallnest/goframe/blob/master/length_field_based_frameconn.go, licensed by Apache License 2.0. It encodes/decodes frames into/from TCP stream with value of the length field in the message.

func NewLengthFieldBasedFrameCodec added in v1.0.0

func NewLengthFieldBasedFrameCodec(ec EncoderConfig, dc DecoderConfig) *LengthFieldBasedFrameCodec

NewLengthFieldBasedFrameCodec instantiates and returns a codec based on the length field. It is the go implementation of netty LengthFieldBasedFrameecoder and LengthFieldPrepender. you can see javadoc of them to learn more details.

func (*LengthFieldBasedFrameCodec) Decode added in v1.0.0

func (cc *LengthFieldBasedFrameCodec) Decode(c Conn) ([]byte, error)

Decode ...

func (*LengthFieldBasedFrameCodec) Encode added in v1.0.0

func (cc *LengthFieldBasedFrameCodec) Encode(c Conn, buf []byte) (out []byte, err error)

Encode ...

type LineBasedFrameCodec added in v1.0.0

type LineBasedFrameCodec struct{}

LineBasedFrameCodec encodes/decodes line-separated frames into/from TCP stream.

func (*LineBasedFrameCodec) Decode added in v1.0.0

func (cc *LineBasedFrameCodec) Decode(c Conn) ([]byte, error)

Decode ...

func (*LineBasedFrameCodec) Encode added in v1.0.0

func (cc *LineBasedFrameCodec) Encode(c Conn, buf []byte) ([]byte, error)

Encode ...

type LoadBalancing added in v1.1.0

type LoadBalancing int

LoadBalancing represents the the type of load-balancing algorithm.

const (
	// RoundRobin assigns the next accepted connection to the event-loop by polling event-loop list.
	RoundRobin LoadBalancing = iota

	// LeastConnections assigns the next accepted connection to the event-loop that is
	// serving the least number of active connections at the current time.
	LeastConnections

	// SourceAddrHash assignes the next accepted connection to the event-loop by hashing the remote address.
	SourceAddrHash
)

type Option added in v1.0.0

type Option func(opts *Options)

Option is a function that will set up option.

func WithCodec added in v1.0.0

func WithCodec(codec ICodec) Option

WithCodec sets up a codec to handle TCP stream.

func WithLoadBalancing added in v1.1.0

func WithLoadBalancing(lb LoadBalancing) Option

WithLoadBalancing sets up the load-balancing algorithm in gnet server.

func WithLockOSThread added in v1.3.0

func WithLockOSThread(lockOSThread bool) Option

WithLockOSThread sets up LockOSThread mode for I/O event-loops.

func WithLogLevel added in v1.4.6

func WithLogLevel(lvl zapcore.Level) Option

WithLogLevel is an option to set up the logging level.

func WithLogPath added in v1.4.6

func WithLogPath(fileName string) Option

WithLogPath is an option to set up the local path of log file.

func WithLogger added in v1.0.0

func WithLogger(logger logging.Logger) Option

WithLogger sets up a customized logger.

func WithMulticore added in v1.0.0

func WithMulticore(multicore bool) Option

WithMulticore sets up multi-cores in gnet server.

func WithNumEventLoop added in v1.0.0

func WithNumEventLoop(numEventLoop int) Option

WithNumEventLoop sets up NumEventLoop in gnet server.

func WithOptions added in v1.0.0

func WithOptions(options Options) Option

WithOptions sets up all options.

func WithReadBufferCap added in v1.4.1

func WithReadBufferCap(readBufferCap int) Option

WithReadBufferCap sets up ReadBufferCap for reading bytes.

func WithReusePort added in v1.0.0

func WithReusePort(reusePort bool) Option

WithReusePort sets up SO_REUSEPORT socket option.

func WithSocketRecvBuffer added in v1.4.3

func WithSocketRecvBuffer(recvBuf int) Option

WithSocketRecvBuffer sets the maximum socket receive buffer in bytes.

func WithSocketSendBuffer added in v1.4.3

func WithSocketSendBuffer(sendBuf int) Option

WithSocketSendBuffer sets the maximum socket send buffer in bytes.

func WithTCPKeepAlive added in v1.0.0

func WithTCPKeepAlive(tcpKeepAlive time.Duration) Option

WithTCPKeepAlive sets up the SO_KEEPALIVE socket option with duration.

func WithTCPNoDelay added in v1.4.0

func WithTCPNoDelay(tcpNoDelay TCPSocketOpt) Option

WithTCPNoDelay enable/disable the TCP_NODELAY socket option.

func WithTicker added in v1.0.0

func WithTicker(ticker bool) Option

WithTicker indicates that a ticker is set.

type Options

type Options struct {
	// Multicore indicates whether the server will be effectively created with multi-cores, if so,
	// then you must take care with synchronizing memory between all event callbacks, otherwise,
	// it will run the server with single thread. The number of threads in the server will be automatically
	// assigned to the value of logical CPUs usable by the current process.
	Multicore bool

	// LockOSThread is used to determine whether each I/O event-loop is associated to an OS thread, it is useful when you
	// need some kind of mechanisms like thread local storage, or invoke certain C libraries (such as graphics lib: GLib)
	// that require thread-level manipulation via cgo, or want all I/O event-loops to actually run in parallel for a
	// potential higher performance.
	LockOSThread bool

	// ReadBufferCap is the maximum number of bytes that can be read from the client when the readable event comes.
	// The default value is 64KB, it can be reduced to avoid starving subsequent client connections.
	//
	// Note that ReadBufferCap will be always converted to the least power of two integer value greater than
	// or equal to its real amount.
	ReadBufferCap int

	// LB represents the load-balancing algorithm used when assigning new connections.
	LB LoadBalancing

	// NumEventLoop is set up to start the given number of event-loop goroutine.
	// Note: Setting up NumEventLoop will override Multicore.
	NumEventLoop int

	// ReusePort indicates whether to set up the SO_REUSEPORT socket option.
	ReusePort bool

	// Ticker indicates whether the ticker has been set up.
	Ticker bool

	// TCPKeepAlive sets up a duration for (SO_KEEPALIVE) socket option.
	TCPKeepAlive time.Duration

	// TCPNoDelay controls whether the operating system should delay
	// packet transmission in hopes of sending fewer packets (Nagle's algorithm).
	//
	// The default is true (no delay), meaning that data is sent
	// as soon as possible after a Write.
	TCPNoDelay TCPSocketOpt

	// SocketRecvBuffer sets the maximum socket receive buffer in bytes.
	SocketRecvBuffer int

	// SocketSendBuffer sets the maximum socket send buffer in bytes.
	SocketSendBuffer int

	// ICodec encodes and decodes TCP stream.
	Codec ICodec

	// LogPath the local path where logs will be written, this is the easiest way to set up client logs,
	// the client instantiates a default uber-go/zap logger with this given log path, you are also allowed to employ
	// you own logger during the client lifetime by implementing the following log.Logger interface.
	//
	// Note that this option can be overridden by the option Logger.
	LogPath string

	// LogLevel indicates the logging level inside client, it should be used along with LogPath.
	LogLevel zapcore.Level

	// Logger is the customized logger for logging info, if it is not set,
	// then gnet will use the default logger powered by go.uber.org/zap.
	Logger logging.Logger
}

Options are set when the client opens.

type Server

type Server struct {

	// Multicore indicates whether the server will be effectively created with multi-cores, if so,
	// then you must take care of synchronizing the shared data between all event callbacks, otherwise,
	// it will run the server with single thread. The number of threads in the server will be automatically
	// assigned to the value of logical CPUs usable by the current process.
	Multicore bool

	// The Addr parameter is the listening address that align
	// with the addr string passed to the Serve function.
	Addr net.Addr

	// NumEventLoop is the number of event-loops that the server is using.
	NumEventLoop int

	// ReusePort indicates whether SO_REUSEPORT is enable.
	ReusePort bool

	// TCPKeepAlive (SO_KEEPALIVE) socket option.
	TCPKeepAlive time.Duration
	// contains filtered or unexported fields
}

Server represents a server context which provides information about the running server and has control functions for managing state.

func (Server) CountConnections added in v1.1.0

func (s Server) CountConnections() (count int)

CountConnections counts the number of currently active connections and returns it.

func (Server) DupFd added in v1.3.2

func (s Server) DupFd() (dupFD int, err error)

DupFd returns a copy of the underlying file descriptor of listener. It is the caller's responsibility to close dupFD when finished. Closing listener does not affect dupFD, and closing dupFD does not affect listener.

type TCPSocketOpt added in v1.4.0

type TCPSocketOpt int

TCPSocketOpt is the type of TCP socket options.

const (
	TCPNoDelay TCPSocketOpt = iota
	TCPDelay
)

Available TCP socket options.

Directories

Path Synopsis
Package logging provides logging functionality for gnet server, it sets up a default logger (powered by go.uber.org/zap) which is about to be used by gnet server, it also allows users to replace the default logger with their customized logger by just implementing the `Logger` interface and assign it to the functional option `Options.Logger`, pass it to `gnet.Serve` method.
Package logging provides logging functionality for gnet server, it sets up a default logger (powered by go.uber.org/zap) which is about to be used by gnet server, it also allows users to replace the default logger with their customized logger by just implementing the `Logger` interface and assign it to the functional option `Options.Logger`, pass it to `gnet.Serve` method.
pool
io
queue
Package queue delivers an implementation of lock-free concurrent queue based on the algorithm presented by Maged M. Michael and Michael L. Scot.
Package queue delivers an implementation of lock-free concurrent queue based on the algorithm presented by Maged M. Michael and Michael L. Scot.
socket
Package socket provides functions that return fd and net.Addr based on given the protocol and address with a SO_REUSEPORT option set to the socket.
Package socket provides functions that return fd and net.Addr based on given the protocol and address with a SO_REUSEPORT option set to the socket.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL