redis服务器是tcp连接,这里我们先写一个基础的TCP服务器,而redis的hanler具体实现今后再写,这里仅实现了监听信号关闭服务,以及优雅的关闭(清理已经有的连接)
至于为什么只写了一个handler.Close(),是因为设计打算把所有的conn放在一个map里面,handler.Close()遍历map关闭所有连接
测试单元只是简单的写写,本篇博文重点是基础的TCP以及优雅的关闭
代码package TCP
import (
"Gotosp/pkg/log"
"context"
"net"
"os"
"os/signal"
"sync"
"syscall"
)
type Handler interface {
Handle(ctx context.Context, conn net.Conn)
Close()
}
type ServerConfig struct {
Address string
}
func StartServer(cfg *ServerConfig, handler Handler) error {
ctx, cancel := context.WithCancel(context.Background())
sigCh := make(chan os.Signal)
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) //监听这些信号
go func() {
<-sigCh
cancel() //收到退出信号,告诉下流开始退出
signal.Stop(sigCh)
close(sigCh)
}()
listener, err := net.Listen("tcp4", cfg.Address)
if err != nil {
return err
}
ListenAndServeWithSignal(ctx, listener, handler)
return nil
}
func ListenAndServeWithSignal(ctx context.Context, listener net.Listener, handler Handler) {
wg := sync.WaitGroup{}
//收到退出通知,开始退出
go func() {
<-ctx.Done()
listener.Close()
handler.Close()
}()
//意外panic导致程序退出
defer func() {
listener.Close()
handler.Close()
}()
for {
conn, err := listener.Accept()
if err != nil {
log.Error("Accept err", err)
break
}
wg.Add(1)
go func() {
defer func() {
wg.Done()
}()
handler.Handle(ctx, conn)
}()
}
wg.Wait()
}
package TCP
import (
"Gotosp/pkg/log"
"bufio"
"context"
"io"
"net"
"sync"
"testing"
)
type echo struct {
activeConn sync.Map
conn net.Conn
}
func (e *echo) Handle(ctx context.Context, conn net.Conn) {
e.conn = conn
e.activeConn.Store(e.conn, struct{}{})
reader := bufio.NewReader(conn)
for {
msg, err := reader.ReadString('\n')
if err != nil {
if err != io.EOF {
log.Error("read err", err)
}
e.activeConn.Delete(e.conn)
conn.Close()
return
}
b := []byte(msg)
conn.Write(b)
}
}
func (e *echo) Close() {
e.activeConn.Range(func(key interface{}, val interface{}) bool {
client := key.(*echo)
client.conn.Close()
return true
})
}
func MakeEcho() *echo {
return &echo{}
}
func TestStartServer(t *testing.T) {
cfg := &ServerConfig{Address: "127.0.0.1:6872"}
err := StartServer(cfg, MakeEcho())
if err != nil {
log.Fatal("start server err", err)
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)