Go 语言中实现优雅的停止程序

来源:互联网 发布:大猩猩和人杂交知乎 编辑:程序博客网 时间:2024/05/22 15:28
/**Go 语言中实现优雅的停止程序主goroutine监听操作系统消息,收到系统停止消息后关闭server的chan,所有子协程检测到chan关闭,则全部退出**/package mainimport ("log""net""os""os/signal""sync""syscall""time")// An uninteresting service.type Service struct {ch        chan boolwaitGroup *sync.WaitGroup}// Make a new Service.func NewService() *Service {return &Service{ch:        make(chan bool),waitGroup: &sync.WaitGroup{},}}// Accept connections and spawn a goroutine to serve each one.  Stop listening// if anything is received on the service's channel.func (s *Service) Serve(listener *net.TCPListener) {s.waitGroup.Add(1)defer s.waitGroup.Done()for {select {case <-s.ch:log.Println("stopping listening on", listener.Addr())listener.Close()returndefault:}listener.SetDeadline(time.Now().Add(1e9))conn, err := listener.AcceptTCP()if nil != err {//判断错误类型是否是net.OpErrorif opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {continue}log.Println(err)}log.Println(conn.RemoteAddr(), "connected")go s.serve(conn)}}// Stop the service by closing the service's channel.  Block until the service// is really stopped.func (s *Service) Stop() {close(s.ch)s.waitGroup.Wait()}// Serve a connection by reading and writing what was read.  That's right, this// is an echo service.  Stop reading and writing if anything is received on the// service's channel but only after writing what was read.func (s *Service) serve(conn *net.TCPConn) {defer conn.Close()s.waitGroup.Add(1)defer s.waitGroup.Done()for {select {case <-s.ch:log.Println("disconnecting", conn.RemoteAddr())returndefault:}conn.SetDeadline(time.Now().Add(1e9))buf := make([]byte, 4096)if _, err := conn.Read(buf); nil != err {if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {continue}log.Println(err)return}if _, err := conn.Write(buf); nil != err {log.Println(err)return}}}func main() {// Listen on 127.0.0.1:48879.  That's my favorite port number because in// hex 48879 is 0xBEEF.laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:48879")if nil != err {log.Fatalln(err)}listener, err := net.ListenTCP("tcp", laddr)if nil != err {log.Fatalln(err)}log.Println("listening on", listener.Addr())// Make a new service and send it into the background.service := NewService()go service.Serve(listener)// Handle SIGINT and SIGTERM.ch := make(chan os.Signal)signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)log.Println("signal:", <-ch)// Stop the service gracefully.service.Stop()}

原创粉丝点击