88 lines
1.7 KiB
Go
88 lines
1.7 KiB
Go
package udp
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"net"
|
|
"runtime/debug"
|
|
)
|
|
|
|
type UdpServer interface {
|
|
Listen() error
|
|
Close()
|
|
}
|
|
|
|
type UdpMsgHandler func(b []byte)
|
|
|
|
type server struct {
|
|
addr string
|
|
conn *net.UDPConn
|
|
handler UdpMsgHandler
|
|
cancelFn context.CancelFunc
|
|
done chan struct{} // 服务协程退出信号
|
|
}
|
|
|
|
// NewServer creates a new instance of UdpServer.
|
|
func NewServer(addr string, handler UdpMsgHandler) UdpServer {
|
|
return &server{addr: addr, handler: handler, done: make(chan struct{})}
|
|
}
|
|
|
|
func (s *server) Listen() error {
|
|
udpAddr, err := net.ResolveUDPAddr("udp", s.addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
conn, err := net.ListenUDP("udp", udpAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.conn = conn
|
|
ctx, cfn := context.WithCancel(context.Background())
|
|
// 启动监听处理
|
|
go s.listenAndHandle(ctx)
|
|
s.cancelFn = cfn
|
|
return nil
|
|
}
|
|
|
|
func (s *server) Close() {
|
|
err := s.conn.Close()
|
|
if err != nil {
|
|
slog.Error("udp server close error", "error", err)
|
|
}
|
|
s.cancelFn()
|
|
<-s.done
|
|
}
|
|
|
|
func (s *server) listenAndHandle(ctx context.Context) {
|
|
defer close(s.done)
|
|
defer s.conn.Close()
|
|
mainLoop:
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
// slog.Info("udp server listen 关闭", "addr", s.addr)
|
|
break mainLoop
|
|
default:
|
|
}
|
|
buf := make([]byte, 1024)
|
|
n, _, err := s.conn.ReadFromUDP(buf)
|
|
if err != nil {
|
|
slog.Error("udp server read error", "addr", s.addr, "error", err)
|
|
continue
|
|
}
|
|
// slog.Debug("udp server handle", "addr", ap.String())
|
|
go s.handle(buf[:n])
|
|
}
|
|
}
|
|
|
|
func (s *server) handle(b []byte) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
slog.Error("udp server handle error", "error", err, "stack", string(debug.Stack()))
|
|
debug.PrintStack()
|
|
}
|
|
}()
|
|
// slog.Info("udp server handle", "msg", string(b))
|
|
s.handler(b)
|
|
}
|