event
is a network I/O event notification library for Go. It uses epoll to poll I/O events that is fast and low memory usage. It works in a similar manner as libevent.
The goal of event
is to provide a BASIC
tool for building high performance network applications.
Note: All development is done on a Raspberry Pi 4B.
- Supports more events
- Flexible timer and ticker
- Supports event priority
- Edge-triggered
- Simple API
- Low memory usage
To start using event
, just run go get
:
$ go get -u github.com/cheng-zhongliang/event
EvRead
fires when the fd is readable.EvWrite
fires when the fd is writable.EvClosed
fires when the connection has closed.EvTimeout
fires when the timeout expires.EvSignal
fires when the os signal arrives.EvPersist
if not set, the event will be deleted after it is triggered.
When the event is triggered, the callback function will be called.
These events can be used in combination.
base := event.NewBase()
ev := event.New(fd, event.EvRead|event.Timeout|event.EvPersist, callback, arg)
base.AddEvent(ev, 1*time.Second)
When the fd is readable or timeout expires, this event will be triggered.
The signal event will be triggered when the os signal arrives.
base := event.NewBase()
ev := event.NewSignal(os.Interrupt, callback, arg)
base.AddEvent(ev, 0)
The timer is a one-shot event that will be triggered after the timeout expires.
base := event.NewBase()
ev := event.NewTimer(callback, arg)
base.AddEvent(ev, 1*time.Second)
The ticker is a repeating event that will be triggered every time the timeout expires.
base := event.NewBase()
ev := event.NewTicker(callback, arg)
base.AddEvent(ev, 1*time.Second)
When events are triggered together, high priority events will be dispatched first.
ev := event.New(fd, event.EvRead|event.EvET, callback, arg)
ev.SetPriority(event.High)
The event is level-triggered by default. If you want to use edge-triggered, you can set the EvET
flag.
ev := event.New(fd, event.EvRead|event.EvET, callback, arg)
Example echo server that binds to port 1246:
package main
import (
"syscall"
"github.com/cheng-zhongliang/event"
)
func main() {
base, err := event.NewBase()
if err != nil {
panic(err)
}
fd := Socket()
ev := event.New(fd, event.EvRead|event.EvPersist, Accept, base)
if err := base.AddEvent(ev, 0); err != nil {
panic(err)
}
exitEv := event.NewSignal(syscall.SIGINT, Exit, base)
if err := base.AddEvent(exitEv, 0); err != nil {
panic(err)
}
if err := base.Dispatch(); err != nil && err != event.ErrBadFileDescriptor {
panic(err)
}
}
func Socket() int {
addr := syscall.SockaddrInet4{Port: 1246, Addr: [4]byte{0, 0, 0, 0}}
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM|syscall.SOCK_NONBLOCK, syscall.IPPROTO_TCP)
if err != nil {
panic(err)
}
if err := syscall.Bind(fd, &addr); err != nil {
panic(err)
}
err = syscall.Listen(fd, syscall.SOMAXCONN)
if err != nil {
panic(err)
}
return fd
}
func Accept(fd int, events uint32, arg interface{}) {
base := arg.(*event.EventBase)
clientFd, _, err := syscall.Accept(fd)
if err != nil {
panic(err)
}
ev := event.New(clientFd, event.EvRead|event.EvPersist, Echo, nil)
if err := base.AddEvent(ev, 0); err != nil {
panic(err)
}
}
func Echo(fd int, events uint32, arg interface{}) {
buf := make([]byte, 0xFFF)
n, err := syscall.Read(fd, buf)
if err != nil {
panic(err)
}
if _, err := syscall.Write(fd, buf[:n]); err != nil {
panic(err)
}
}
func Exit(fd int, events uint32, arg interface{}) {
base := arg.(*event.EventBase)
if err := base.Exit(); err != nil {
panic(err)
}
}
Connect to the echo server:
$ telnet localhost 1246