event
is a network I/O event notification library for Go. It uses epoll and kqueue 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 Read/Write/Timeout events
- Flexible timer event and ticker event
- Supports event priority
- 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.EvTimeout
fires when the timeout expires.
When the event is triggered, the callback function will be called.
These events can be used in combination.
base := event.NewBase()
ev := event.New(base, fd, event.EvRead|event.Timeout, callback, arg)
ev.Attach(time.Second)
When the fd is readable or timeout expires, this event will be triggered.
The event is one-shot by default. If you want to persist, you can set the EvPersist
option.
ev := event.New(base, fd, event.EvRead|event.EvPersist, callback, arg)
The timer is a one-shot event that will be triggered after the timeout expires.
base := event.NewBase()
ev := event.NewTimer(base, callback, arg)
ev.Attach(time.Second)
The ticker is a repeating event that will be triggered every time the timeout expires.
base := event.NewBase()
ev := event.NewTicker(base, callback, arg)
ev.Attach(time.Second)
When events are triggered together, high priority events will be dispatched first.
ev := event.New(base, fd, event.EvRead, callback, arg)
ev.SetPriority(event.HP)
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(base, fd, event.EvRead|event.EvPersist, accept, base)
if err := ev.Attach(0); err != nil {
panic(err)
}
if err := base.Dispatch(); err != nil && err != syscall.EBADF {
panic(err)
}
syscall.Close(fd)
}
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.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(base, clientFd, event.EvRead|event.EvPersist, echo, nil)
if err := ev.Attach(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)
}
}
Connect to the echo server:
$ telnet localhost 1246