Convert Figma logo to code with AI

lesismal logonbio

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.

2,151
151
2,151
2

Top Related Projects

9,481

🚀 gnet is a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go.

21,607

Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http

5,880

Fast event-loop networking for Go

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

  1. 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()
  1. 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()
  1. 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:

  1. Install the package:

    go get github.com/lesismal/nbio
    
  2. Import the package in your Go code:

    import "github.com/lesismal/nbio"
    
  3. Create an engine with desired configuration:

    engine := nbio.NewEngine(nbio.Config{
        Network: "tcp",
        Addr:    ":8888",
    })
    
  4. Set up event handlers and start the engine:

    engine.OnData(func(c *nbio.Conn, data []byte) {
        // Handle incoming data
    })
    engine.Start()
    

Competitor Comparisons

9,481

🚀 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.

21,607

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.

5,880

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 Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

NBIO - NON-BLOCKING IO

Mentioned in Awesome Go MIT licensed Go Version Build Status Go Report Card

Contents

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

IOModRemarks
IOModNonBlockingThere's no difference between this IOMod and the old version with no IOMod. All the connections will be handled by poller.
IOModBlockingAll 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.
IOModMixedWe 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:

Star History

Star History Chart