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