nbio
Pure Go 1000k+ connections solution, support tls/http1.x/websocket and basically compatible with net/http, with high-performance and low memory cost, non-blocking, event-driven, easy-to-use.
Top Related Projects
Quick Overview
NBIO is a high-performance, non-blocking I/O networking framework for Go. It provides an efficient and scalable alternative to the standard net package, offering support for TCP, UDP, and Unix domain sockets with a focus on performance and ease of use.
Pros
- High performance and low latency for network operations
- Supports multiple protocols (TCP, UDP, Unix domain sockets)
- Easy to use API, similar to the standard net package
- Designed for scalability and efficient resource utilization
Cons
- May require some code changes when migrating from the standard net package
- Less mature compared to the standard library implementation
- Limited documentation and examples compared to more established libraries
- Potential learning curve for developers unfamiliar with non-blocking I/O concepts
Code Examples
- Creating a TCP server:
import "github.com/lesismal/nbio"
engine := nbio.NewEngine(nbio.Config{
Network: "tcp",
Addr: ":8888",
})
engine.OnData(func(c *nbio.Conn, data []byte) {
c.Write(data) // Echo server
})
engine.Start()
- Creating a UDP server:
import "github.com/lesismal/nbio"
engine := nbio.NewEngine(nbio.Config{
Network: "udp",
Addr: ":8888",
})
engine.OnData(func(c *nbio.Conn, data []byte) {
c.WriteTo(data, c.RemoteAddr()) // Echo server
})
engine.Start()
- Creating a client connection:
import "github.com/lesismal/nbio"
engine := nbio.NewEngine(nbio.Config{})
conn, err := engine.Dial("tcp", "example.com:80")
if err != nil {
// Handle error
}
conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"))
Getting Started
To use NBIO in your Go project, follow these steps:
-
Install the package:
go get github.com/lesismal/nbio
-
Import the package in your Go code:
import "github.com/lesismal/nbio"
-
Create an engine with desired configuration:
engine := nbio.NewEngine(nbio.Config{ Network: "tcp", Addr: ":8888", })
-
Set up event handlers and start the engine:
engine.OnData(func(c *nbio.Conn, data []byte) { // Handle incoming data }) engine.Start()
Competitor Comparisons
🚀 gnet is a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go.
Pros of gnet
- Higher performance in some benchmarks, especially for high-concurrency scenarios
- More comprehensive documentation and examples
- Built-in support for load balancing and connection pooling
Cons of gnet
- More complex API, which may have a steeper learning curve
- Less flexible in terms of customization and extension
- Larger codebase, potentially leading to more maintenance overhead
Code Comparison
nbio example:
engine := nbio.NewEngine(nbio.Config{
Network: "tcp",
Addr: ":8888",
})
engine.OnData(func(c *nbio.Conn, data []byte) {
c.Write(data)
})
engine.Start()
gnet example:
type echoServer struct {
*gnet.EventServer
}
func (es *echoServer) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
out = frame
return
}
gnet.Serve(&echoServer{}, "tcp://:9000", gnet.WithMulticore(true))
Both libraries provide efficient networking capabilities for Go applications, but they differ in their approach and feature set. nbio offers a simpler API and more flexibility, while gnet focuses on high performance and built-in features for specific use cases. The choice between them depends on the specific requirements of your project and your familiarity with their respective APIs.
Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http
Pros of fasthttp
- Higher performance and lower memory usage for HTTP operations
- More mature and widely adopted in production environments
- Extensive feature set for HTTP handling, including routing and middleware support
Cons of fasthttp
- Limited to HTTP/1.1 protocol, lacking HTTP/2 support
- Steeper learning curve due to its non-standard API design
- Less compatibility with standard Go net/http packages
Code Comparison
fasthttp example:
func requestHandler(ctx *fasthttp.RequestCtx) {
fmt.Fprintf(ctx, "Hello, world!")
}
fasthttp.ListenAndServe(":8080", requestHandler)
nbio example:
engine := nbio.NewEngine(nbio.Config{})
engine.OnData(func(c *nbio.Conn, data []byte) {
c.Write([]byte("Hello, world!"))
})
engine.Start()
nbio is a more general-purpose networking library, offering support for various protocols beyond HTTP. It provides a simpler API for basic networking tasks but may require additional implementation for full HTTP functionality. fasthttp, on the other hand, is specifically designed for HTTP handling and offers optimized performance for web applications.
While fasthttp excels in HTTP-specific scenarios, nbio's flexibility makes it suitable for a broader range of networking applications. The choice between the two depends on the specific requirements of your project, with fasthttp being ideal for high-performance HTTP servers and nbio offering versatility for diverse networking needs.
Fast event-loop networking for Go
Pros of evio
- More mature project with longer development history
- Extensive documentation and examples
- Wider adoption and community support
Cons of evio
- Less active development in recent years
- May have higher memory usage in some scenarios
- Limited cross-platform support compared to nbio
Code Comparison
evio example:
func main() {
if err := evio.Serve(events, "tcp://localhost:5000"); err != nil {
panic(err)
}
}
nbio example:
func main() {
svr := nbio.NewGopher(nbio.Config{
Network: "tcp",
Addr: ":5000",
})
svr.OnData(onData)
svr.Start()
}
Both libraries provide event-driven, non-blocking I/O for Go applications. evio offers a simpler API with a single Serve
function, while nbio uses a more object-oriented approach with a Gopher
struct and separate method calls for configuration and event handling.
evio has been around longer and has more extensive documentation, making it easier for newcomers to get started. However, nbio is more actively maintained and offers better cross-platform support, including Windows compatibility.
In terms of performance, both libraries are highly efficient, but nbio may have an edge in memory usage for certain workloads. The choice between the two often comes down to specific project requirements and personal preference.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
NBIO - NON-BLOCKING IO
Contents
- NBIO - NON-BLOCKING IO
Features
Cross Platform
- Linux: Epoll with LT/ET/ET+ONESHOT supported, LT as default
- BSD(MacOS): Kqueue
- Windows: Based on std net, for debugging only
Protocols Supported
- TCP/UDP/Unix Socket supported
- TLS supported
- HTTP/HTTPS 1.x supported
- Websocket supported, Passes the Autobahn Test Suite,
OnOpen/OnMessage/OnClose
order guaranteed
Interfaces
- Implements a non-blocking net.Conn(except windows)
- SetDeadline/SetReadDeadline/SetWriteDeadline supported
- Concurrent Write/Close supported(both nbio.Conn and nbio/nbhttp/websocket.Conn)
Quick Start
package main
import (
"log"
"github.com/lesismal/nbio"
)
func main() {
engine := nbio.NewEngine(nbio.Config{
Network: "tcp",//"udp", "unix"
Addrs: []string{":8888"},
MaxWriteBufferSize: 6 * 1024 * 1024,
})
// hanlde new connection
engine.OnOpen(func(c *nbio.Conn) {
log.Println("OnOpen:", c.RemoteAddr().String())
})
// hanlde connection closed
engine.OnClose(func(c *nbio.Conn, err error) {
log.Println("OnClose:", c.RemoteAddr().String(), err)
})
// handle data
engine.OnData(func(c *nbio.Conn, data []byte) {
c.Write(append([]byte{}, data...))
})
err := engine.Start()
if err != nil {
log.Fatalf("nbio.Start failed: %v\n", err)
return
}
defer engine.Stop()
<-make(chan int)
}
Examples
TCP Echo Examples
UDP Echo Examples
TLS Examples
HTTP Examples
HTTPS Examples
Websocket Examples
Websocket TLS Examples
Use With Other STD Based Frameworkds
More Examples
1M Websocket Connections Benchmark
For more details: go-websocket-benchmark
# lsb_release -a
LSB Version: core-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch
Distributor ID: Ubuntu
Description: Ubuntu 20.04.6 LTS
Release: 20.04
Codename: focal
# free
total used free shared buff/cache available
Mem: 24969564 15656352 3422212 1880 5891000 8899604
Swap: 0 0 0
# cat /proc/cpuinfo | grep processor
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7
processor : 8
processor : 9
processor : 10
processor : 11
processor : 12
processor : 13
processor : 14
processor : 15
# taskset
run nbio_nonblocking server on cpu 0-7
--------------------------------------------------------------
BenchType : BenchEcho
Framework : nbio_nonblocking
TPS : 104713
EER : 280.33
Min : 56.90us
Avg : 95.36ms
Max : 2.29s
TP50 : 62.82ms
TP75 : 65.38ms
TP90 : 89.38ms
TP95 : 409.55ms
TP99 : 637.95ms
Used : 47.75s
Total : 5000000
Success : 5000000
Failed : 0
Conns : 1000000
Concurrency: 10000
Payload : 1024
CPU Min : 0.00%
CPU Avg : 373.53%
CPU Max : 602.33%
MEM Min : 978.70M
MEM Avg : 979.88M
MEM Max : 981.14M
--------------------------------------------------------------
Magics For HTTP and Websocket
Different IOMod
IOMod | Remarks |
---|---|
IOModNonBlocking | There's no difference between this IOMod and the old version with no IOMod. All the connections will be handled by poller. |
IOModBlocking | All the connections will be handled by at least one goroutine, for websocket, we can set Upgrader.BlockingModAsyncWrite=true to handle writing with a separated goroutine and then avoid Head-of-line blocking on broadcasting scenarios. |
IOModMixed | We set the Engine.MaxBlockingOnline, if the online num is smaller than it, the new connection will be handled by single goroutine as IOModBlocking, else the new connection will be handled by poller. |
The IOModBlocking
aims to improve the performance for low online service, it runs faster than std.
The IOModMixed
aims to keep a balance between performance and cpu/mem cost in different scenarios: when there are not too many online connections, it performs better than std, or else it can serve lots of online connections and keep healthy.
Using Websocket With Std Server
package main
import (
"fmt"
"net/http"
"github.com/lesismal/nbio/nbhttp/websocket"
)
var (
upgrader = newUpgrader()
)
func newUpgrader() *websocket.Upgrader {
u := websocket.NewUpgrader()
u.OnOpen(func(c *websocket.Conn) {
// echo
fmt.Println("OnOpen:", c.RemoteAddr().String())
})
u.OnMessage(func(c *websocket.Conn, messageType websocket.MessageType, data []byte) {
// echo
fmt.Println("OnMessage:", messageType, string(data))
c.WriteMessage(messageType, data)
})
u.OnClose(func(c *websocket.Conn, err error) {
fmt.Println("OnClose:", c.RemoteAddr().String(), err)
})
return u
}
func onWebsocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
panic(err)
}
fmt.Println("Upgraded:", conn.RemoteAddr().String())
}
func main() {
mux := &http.ServeMux{}
mux.HandleFunc("/ws", onWebsocket)
server := http.Server{
Addr: "localhost:8080",
Handler: mux,
}
fmt.Println("server exit:", server.ListenAndServe())
}
Credits
Contributors
Thanks Everyone:
- acgreek
- acsecureworks
- arunsathiya
- guonaihong
- isletnet
- liwnn
- manjun21
- om26er
- rfyiamcool
- sunny352
- sunvim
- wuqinqiang
- wziww
- youzhixiaomutou
- zbh255
- IceflowRE
- YanKawaYu
Star History
Top Related Projects
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot