donglizuo8892 2017-04-18 13:19
浏览 28
已采纳

正常关闭多个服务器

I have an application that runs a basic HTTP server and also accepts connections over TCP.

Basic pseudo code is as follows:

package main

import (
    "log"
    "net"
    "net/http"
)

func main() {
    // create serve HTTP server.
    serveSvr := http.NewServeMux()
    serveSvr.HandleFunc("/", handler())

    // create server error channel
    svrErr := make(chan error)

    // start HTTP server.
    go func() {
        svrErr <- http.ListenAndServe(":8080", serveSvr)
    }()

    // start TCP server
    go func() {
        lnr, err := net.Listen("tcp", ":1111")
        if err != nil {
            svrErr <- err
            return
        }
        defer lnr.Close()

        for {
            conn, err := lnr.Accept()
            if err != nil {
                log.Printf("connection error: %v", err)
                continue
            }
            // code to handle each connection
        }
    }()

    select {
    case err := <-svrErr:
        log.Print(err)
    }
}

I run both servers in separate goroutines and I need a way to gracefully shut them both down if either of them fail. For example; if the HTTP server errors, how would I go back and shutdown the TCP server/perform any cleanup?

  • 写回答

1条回答 默认 最新

  • douzhi9921 2017-04-18 14:17
    关注

    Start by keeping a reference to the http server and the tcp listener so that you can later close them.

    Create separate error channels so you know which path returned the error, and buffer them so that a send can always complete.

    To make sure that whatever cleanup you want to attempt is complete before you exit, you can add a WaitGroup to the server goroutines.

    I simple extension of your example might look like:

    var wg sync.WaitGroup
    
    // create  HTTP server.
    serveSvr := http.NewServeMux()
    serveSvr.HandleFunc("/", handler())
    server := &http.Server{Addr: ":8080", Handler: serveSvr}
    
    // create http server error channel
    httpErr := make(chan error, 1)
    
    // start HTTP server.
    wg.Add(1)
    go func() {
        defer wg.Done()
        httpErr <- server.ListenAndServe()
        // http cleanup
    }()
    
    tcpErr := make(chan error, 1)
    listener, err := net.Listen("tcp", ":1111")
    if err != nil {
        tcpErr <- err
    } else {
        // start TCP server
        wg.Add(1)
        go func() {
            defer wg.Done()
            defer listener.Close()
            for {
                conn, err := listener.Accept()
                if err != nil {
                    if ne, ok := err.(net.Error); ok && ne.Temporary() {
                        // temp error, wait and continue
                        continue
                    }
                    tcpErr <- err
    
                    // cleanup TCP
                    return
                }
    
                // code to handle each connection
            }
        }()
    }
    select {
    case err := <-httpErr:
        // handle http error and close tcp listen
        if listener != nil {
            listener.Close()
        }
    case err := <-tcpErr:
        // handle tcp error and close http server
        server.Close()
    }
    
    // you may also want to receive the error from the server
    // you shutdown to log
    
    // wait for any final cleanup to finish
    wg.Wait()
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?
  • ¥15 matlab(相关搜索:紧聚焦)