Golang实现redis系列-(2)基础的TCP

Golang实现redis系列-(2)基础的TCP,第1张

基础的TCP 思路代码

思路

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)
	}
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/995189.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存