为了账号安全,请及时绑定邮箱和手机立即绑定

如何在Go中停止侦听服务器

如何在Go中停止侦听服务器

Go
慕斯709654 2021-05-14 10:44:03
我一直试图找到一种方法来优雅地停止Go中的监听服务器。因为有listen.Accept块,所以有必要关闭侦听套接字以发出结束信号,但由于未导出相关错误,因此我无法分辨该错误以及其他任何错误。我可以做得更好吗?请参阅FIXME下面的代码serve()package mainimport (    "io"    "log"    "net"    "time")// Echo server structtype EchoServer struct {    listen net.Listener    done   chan bool}// Respond to incoming connection//// Write the address connected to then echofunc (es *EchoServer) respond(remote *net.TCPConn) {    defer remote.Close()    _, err := io.Copy(remote, remote)    if err != nil {        log.Printf("Error: %s", err)    }}// Listen for incoming connectionsfunc (es *EchoServer) serve() {    for {        conn, err := es.listen.Accept()        // FIXME I'd like to detect "use of closed network connection" here        // FIXME but it isn't exported from net        if err != nil {            log.Printf("Accept failed: %v", err)            break        }        go es.respond(conn.(*net.TCPConn))    }    es.done <- true}// Stop the server by closing the listening listenfunc (es *EchoServer) stop() {    es.listen.Close()    <-es.done}// Make a new echo serverfunc NewEchoServer(address string) *EchoServer {    listen, err := net.Listen("tcp", address)    if err != nil {        log.Fatalf("Failed to open listening socket: %s", err)    }    es := &EchoServer{        listen: listen,        done:   make(chan bool),    }    go es.serve()    return es}// Mainfunc main() {    log.Println("Starting echo server")    es := NewEchoServer("127.0.0.1:18081")    // Run the server for 1 second    time.Sleep(1 * time.Second)    // Close the server    log.Println("Stopping echo server")    es.stop()}此打印2012/11/16 12:53:35 Starting echo server2012/11/16 12:53:36 Stopping echo server2012/11/16 12:53:36 Accept failed: accept tcp 127.0.0.1:18081: use of closed network connection我想隐藏Accept failed消息,但是显然我不想掩盖其他Accept可以报告的错误。我当然可以查看错误测试,use of closed network connection但这确实很丑陋。我可以设置一个标志,说如果要设置,我将要关闭并忽略错误-有更好的方法吗?
查看完整描述

2 回答

?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

accept()调用后立即在循环中检查一些“是否该停止了”标志,然后从中将其翻转main,然后连接到侦听端口以获取服务器套接字“未卡住”的标志。这与旧的“自管技巧”非常相似。


查看完整回答
反对 回复 2021-05-24
?
侃侃无极

TA贡献2051条经验 获得超10个赞

我可以通过在关闭连接之前使用es.done发送信号来处理此问题。除了以下代码,您还需要使用make(chan bool,1)创建es.done,以便我们可以在其中添加单个值而不会阻塞。


// Listen for incoming connections

func (es *EchoServer) serve() {

  for {

    conn, err := es.listen.Accept()

    if err != nil {

      select {

      case <-es.done:

        // If we called stop() then there will be a value in es.done, so

        // we'll get here and we can exit without showing the error.

      default:

        log.Printf("Accept failed: %v", err)

      }

      return

    }

    go es.respond(conn.(*net.TCPConn))

  }

}


// Stop the server by closing the listening listen

func (es *EchoServer) stop() {

  es.done <- true   // We can advance past this because we gave it buffer of 1

  es.listen.Close() // Now it the Accept will have an error above

}


查看完整回答
反对 回复 2021-05-24
  • 2 回答
  • 0 关注
  • 275 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信