golang轻量级I/O事件通知库插件event的使用
Golang轻量级I/O事件通知库插件event的使用
event
是一个用于Go的网络I/O事件通知库。它使用epoll和kqueue来轮询I/O事件,速度快且内存占用低。它的工作方式类似于libevent。
event
的目标是为构建高性能网络应用程序提供基础工具。
特性
- 支持读/写/超时事件
- 灵活的定时器和定时器事件
- 支持事件优先级
- 简单的API
- 低内存使用
安装
要开始使用event
,只需运行go get
:
go get -u github.com/cheng-zhongliang/event
事件类型
EvRead
:当文件描述符可读时触发EvWrite
:当文件描述符可写时触发EvTimeout
:当超时到期时触发
当事件被触发时,回调函数将被调用。
读/写/超时事件
这些事件可以组合使用:
base := event.NewBase()
ev := event.New(base, fd, event.EvRead|event.Timeout, callback, arg)
ev.Attach(time.Second)
当文件描述符可读或超时到期时,此事件将被触发。
选项
事件默认是一次性的。如果要持久化,可以设置EvPersist
选项:
ev := event.New(base, fd, event.EvRead|event.EvPersist, callback, arg)
定时器
定时器是一个一次性事件,将在超时到期后触发:
base := event.NewBase()
ev := event.NewTimer(base, callback, arg)
ev.Attach(time.Second)
定时器
定时器是一个重复事件,每次超时到期时都会触发:
base := event.NewBase()
ev := event.NewTicker(base, callback, arg)
ev.Attach(time.Second)
优先级
当事件同时触发时,高优先级事件将优先分发:
ev := event.New(base, fd, event.EvRead, callback, arg)
ev.SetPriority(event.HP)
使用示例
以下是一个绑定到端口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)
}
}
连接到回显服务器:
telnet localhost 1246
更多关于golang轻量级I/O事件通知库插件event的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang轻量级I/O事件通知库插件event的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang轻量级I/O事件通知库event使用指南
event是一个轻量级的Go语言I/O事件通知库,它提供了一种简单的方式来监控文件描述符上的I/O事件。下面我将详细介绍如何使用这个库。
安装
首先安装event库:
go get github.com/smallnest/event
基本使用
1. 创建事件循环
package main
import (
"fmt"
"github.com/smallnest/event"
"os"
"time"
)
func main() {
// 创建事件循环
loop, err := event.NewEventLoop()
if err != nil {
fmt.Println("Failed to create event loop:", err)
return
}
defer loop.Close()
// 启动事件循环
go loop.Run()
// 在这里添加事件监控...
}
2. 监控文件描述符
func watchFile(loop *event.EventLoop) {
// 打开文件
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("Failed to open file:", err)
return
}
defer file.Close()
// 添加读事件监控
err = loop.AddRead(file.Fd(), func(fd uintptr, extra interface{}) {
fmt.Printf("File %d is readable\n", fd)
// 读取文件内容
buf := make([]byte, 1024)
n, err := file.Read(buf)
if err != nil {
fmt.Println("Read error:", err)
return
}
fmt.Printf("Read %d bytes: %s\n", n, string(buf[:n]))
}, nil)
if err != nil {
fmt.Println("Failed to add read event:", err)
}
}
3. 监控定时器事件
func watchTimer(loop *event.EventLoop) {
// 添加定时器
timerID, err := loop.AddTimer(2*time.Second, true, func(fd uintptr, extra interface{}) {
fmt.Println("Timer fired!")
}, nil)
if err != nil {
fmt.Println("Failed to add timer:", err)
return
}
// 5秒后删除定时器
time.AfterFunc(5*time.Second, func() {
loop.DeleteTimer(timerID)
fmt.Println("Timer removed")
})
}
高级特性
1. 监控网络socket
func watchSocket(loop *event.EventLoop) {
// 创建TCP监听
ln, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("Listen error:", err)
return
}
defer ln.Close()
// 监控监听socket的可读事件(新连接)
err = loop.AddRead(ln.(*net.TCPListener).Fd(), func(fd uintptr, extra interface{}) {
conn, err := ln.Accept()
if err != nil {
fmt.Println("Accept error:", err)
return
}
fmt.Println("New connection from:", conn.RemoteAddr())
// 监控新连接的读事件
go handleConnection(loop, conn.(*net.TCPConn))
}, nil)
if err != nil {
fmt.Println("Failed to monitor listener:", err)
}
}
func handleConnection(loop *event.EventLoop, conn *net.TCPConn) {
defer conn.Close()
err := loop.AddRead(conn.Fd(), func(fd uintptr, extra interface{}) {
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
fmt.Println("Read error:", err)
loop.Delete(fd) // 移除监控
return
}
fmt.Printf("Received %d bytes: %s\n", n, string(buf[:n]))
}, nil)
if err != nil {
fmt.Println("Failed to monitor connection:", err)
}
}
2. 事件优先级
event库支持设置事件优先级:
// 添加高优先级读事件
err := loop.AddReadWithPriority(file.Fd(), event.HighPriority, func(fd uintptr, extra interface{}) {
// 处理高优先级事件
}, nil)
注意事项
- 事件回调函数应该尽量快速执行,避免阻塞事件循环
- 在回调函数中删除当前事件是安全的
- 跨goroutine调用EventLoop的方法需要自己处理同步问题
- 文件描述符关闭后会自动从事件循环中移除
完整示例
package main
import (
"fmt"
"github.com/smallnest/event"
"os"
"time"
)
func main() {
loop, err := event.NewEventLoop()
if err != nil {
fmt.Println("Failed to create event loop:", err)
return
}
defer loop.Close()
go loop.Run()
// 监控文件
watchFile(loop)
// 监控定时器
watchTimer(loop)
// 运行10秒
time.Sleep(10 * time.Second)
}
func watchFile(loop *event.EventLoop) {
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("Failed to open file:", err)
return
}
defer file.Close()
err = loop.AddRead(file.Fd(), func(fd uintptr, extra interface{}) {
buf := make([]byte, 1024)
n, err := file.Read(buf)
if err != nil {
fmt.Println("Read error:", err)
return
}
fmt.Printf("Read %d bytes: %s\n", n, string(buf[:n]))
}, nil)
if err != nil {
fmt.Println("Failed to add read event:", err)
}
}
func watchTimer(loop *event.EventLoop) {
timerID, err := loop.AddTimer(2*time.Second, true, func(fd uintptr, extra interface{}) {
fmt.Println("Timer fired!")
}, nil)
if err != nil {
fmt.Println("Failed to add timer:", err)
return
}
time.AfterFunc(5*time.Second, func() {
loop.DeleteTimer(timerID)
fmt.Println("Timer removed")
})
}
event库是一个轻量级的解决方案,适合需要简单I/O事件通知的场景。对于更复杂的应用,可以考虑使用更全面的库如gnet或evio。