Skip to content
/ liblpc Public

Golang high performance, event-driven, asynchronous I/O

License

Notifications You must be signed in to change notification settings

gen-iot/liblpc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

liblpc

High performance async network io library

go report license Maintenance PRs Welcome Ask Me Anything !

First

if you have any good feature suggestions or bug fixed , any Pull Request or Issues are welcome!

Usage

# install liblpc v2
go get -u github.com/gen-iot/liblpc/v2@latest
// import 
import "github.com/gen-iot/liblpc/v2"

Overview

  • World Based On Event Loop 😎
  • UnBuffered/Buffered Stream πŸš€
  • Timers: IO Timeout, Delay... ⏰
  • DNS Resolve 🌐
  • Lots Of Unix Socket API Toolbox πŸ”§
  • Thread(Goroutine) Safe! πŸ‘

Backend

Platform Backend Support
Linux family Epoll Done πŸŽ‰
mac OS
(BSD family)
Kqueue Done πŸŽ‰
Windows IOCP Maybe Never... 😒
POSIX Like Poll Maybe Never... πŸ₯Ί
we already have epoll
POSIX Like Select Coming Soon 🀑

liblpc using interface Poller and Watcher as abstraction for any backend.

Getting Started

Create Pure EventLoop:

loop,err := liblpc.NewEventLoop()
std.AssertError(err, "new pure event loop")

Create IO EventLoop:

loop, err := liblpc.NewIOEvtLoop(1024 * 4)
std.AssertError(err, "new io event loop")

Loop Lifecycle:

exit a loop

// just call loop.Break in anywhere
loop.Break()

πŸ“ŒLoop.'Close' can't stop a loop but Loop.'Break' can.

πŸ“ŒLoop.'Close' use to cleanup a loop

Cleanup a loop

loop ,err := liblpc.NewEventLoop()
std.AssertError(err, "new event loop")
defer loop.Close()

Run loop synchronously

// block until break loop called
loop.Run()

Run loop asynchronouslyπŸ˜‚πŸ˜‚πŸ˜‚

go func(){ loop.Run() }()

Create Listener:

// create listen fd first!
listenerFd, err := liblpc.NewListenerFd(
  "127.0.0.1:12345", // serve at
  1024,              // backlog
  true,              // enable reuse addr
  true,              // enable reuse port
)
std.AssertError(err, "new listener fd")
// new listener
listener := liblpc.NewListener(loop, int(listenerFd), onAccept)
listener.Start()

Accept New Conn Stream:

// πŸ“ŒNote: in accept callback
stream := liblpc.NewConnStream(
  ln.Loop().(*liblpc.IOEvtLoop), // cast Loop to IOEventLoop 
  newFd,                         // incoming fd
  onStreamRead,                  // read callback
  )
stream.SetOnClose(onStreamClose) // register close callback
stream.Start()

Create Client Stream:

cliFd, err := liblpc.NewConnFd(addr)
std.AssertError(err, "new client fd failed")
stream := liblpc.NewConnStream(loop, int(cliFd), nil)
stream.SetOnConnect(func(sw liblpc.StreamWriter, err error) {
  sw.Write([]byte("hello world!"), true)
})
stream.SetOnClose(func(sw liblpc.StreamWriter, err error) {
  log.Println("client close :", err)
  // break loop...
  loop.Break()
})
stream.Start()

πŸ“ŒStream.'Close' is safe to invoke multi times

πŸ“ŒAnytime you can't find out whether if Stream is 'Closing' or really been 'Closed',Just invoke Stream.'Close'

Example: Simple Read/Write/Close

package main

import (
  "github.com/gen-iot/liblpc"
  "github.com/gen-iot/std"
  "log"
)

func onStreamRead(sw liblpc.StreamWriter, data []byte, len int) {
  // print client data in string format
  log.Println("on read:", string(data[:len]))
  _ = sw.Close()
}

func onStreamClose(sw liblpc.StreamWriter, err error) {
  log.Println("conn closed,err:", err)
  _ = sw.Close() // close remote client
}

func onAccept(ln *liblpc.Listener, newFd int, err error) {
  if err != nil {
    log.Printf("listener got error:%v\n", err)
    return
  }
  stream := liblpc.NewConnStream(
    ln.Loop().(*liblpc.IOEvtLoop), // cast Loop to   IOEventLoop 
    newFd,                         // incoming fd
    onStreamRead,                  // read callback
    )
  stream.SetOnClose(onStreamClose) // register close   callback
  stream.Start()
}

func simpleClient(loop *liblpc.IOEvtLoop, addr string) {
  cliFd, err := liblpc.NewConnFd(addr)
  std.AssertError(err, "new client fd failed")
  stream := liblpc.NewConnStream(loop, int(cliFd), nil)
  stream.SetOnConnect(func(sw liblpc.StreamWriter, err   error) {
    sw.Write([]byte("hello world!"), true)
  })
  stream.SetOnClose(func(sw liblpc.StreamWriter, err error)   {
    log.Println("client close :", err)
    // close itself
    _ = sw.Close()
    // break loop...
    loop.Break()
  })
  stream.Start()
}

func main() {
  loop, err := liblpc.NewIOEvtLoop(1024 * 4)
  std.AssertError(err, "new event loop")
  defer std.CloseIgnoreErr(loop)
  // create listen fd first!
  listenerFd, err := liblpc.NewListenerFd(
    "127.0.0.1:12345", // serve at
    1024,              // backlog
    true,              // enable reuse addr
    true,              // enable reuse port
  )
  std.AssertError(err, "new listener fd")
  // new listener
  listener := liblpc.NewListener(loop, int(listenerFd),   onAccept)
  defer std.CloseIgnoreErr(listener)
  listener.Start()
  // start simple client
  simpleClient(loop, "127.0.0.1:12345")
  //
  loop.Run()
}

License

Released under the MIT License