使用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已经关闭可以做一些后续处理然后再返回,达到了优雅退出的效果。
网友评论