美文网首页
如何优雅的关闭net.Listeners

如何优雅的关闭net.Listeners

作者: qinxiuchen | 来源:发表于2017-07-18 16:42 被阅读0次

    使用golang做网络应用时,创建网络服务器时需要用到net.Listeners生成一个监听器,阻塞处理连接到服务器的请求,如下所示:

    func main(){
        ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", 1234))
        if err != nil {
            log.Fatal(err)
        }
        log.Println("server start...")
        for {
            conn, err := ln.Accept()
            if err != nil {
                log.Fatal(err)
            }
            handle(conn)
        }
    }
    

    但是ln.Accept()是一个阻塞函数,我们无法在某时刻通知并令其退出(处于一个for循环之中),并且有时我们需要在关闭监听器之后做一些收尾或清理的操作。对于一个常驻进程,只能通过杀进程的方式结束,无法满足这些需求,确实不是一个优雅的处理方式。
    在这里我们使用channel的思想来解决这一问题,具体实现如下:

    package main
    
    import (
        "fmt"
        "log"
        "net"
        "time"
    )
    
    var (
        quit = make(chan struct{})
        ln   net.Listener
    )
    
    func main() {
    
        ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", 1234))
        if err != nil {
            log.Fatal(err)
        }
        go start()
        time.Sleep(1 * time.Second)
        stop()
        time.Sleep(1 * time.Second)
    }
    
    func start() {
        log.Println("server start...")
        for {
            conn, err := ln.Accept()
            if err != nil {
                select {
                default:
                case <-quit:
                    //do something
                    return
                }
                fmt.Println(err)
            }
            handle(conn)
        }
    }
    func stop() {
        close(quit)
        ln.Close()
    }
    
    //handle connection
    func handle(conn net.Conn) {
        //......
    }
    
    

    增加了一个叫quit的channel,当我们关闭listener的时候也关闭此channel,监听器报错以后检测到quit已经关闭可以做一些后续处理然后再返回,达到了优雅退出的效果。

    相关文章

      网友评论

          本文标题:如何优雅的关闭net.Listeners

          本文链接:https://www.haomeiwen.com/subject/myshkxtx.html