zinx icon indicating copy to clipboard operation
zinx copied to clipboard

我需要手动控制服务器的开启关闭, 但Stop()后, tcplistener不被关闭

Open markity opened this issue 3 years ago • 1 comments

对zinx/examples/zinx_server中的main.go文件中的main函数小小地修改,如下

// zinx/examples/zinx_server/main.go

func main() {
	//创建一个server句柄
	s := znet.NewServer()

	//注册链接hook回调函数
	s.SetOnConnStart(DoConnectionBegin)
	s.SetOnConnStop(DoConnectionLost)

	//配置路由
	s.AddRouter(0, &zrouter.PingRouter{})
	s.AddRouter(1, &zrouter.HelloZinxRouter{})

	//开启服务
	s.Start()

	time.Sleep(time.Second * 10)

	s.Stop()

	time.Sleep(time.Second * 10)

	s.Serve()
}

运行时终端打印如下

                                        
              ██
              ▀▀
 ████████   ████     ██▄████▄  ▀██  ██▀
     ▄█▀      ██     ██▀   ██    ████
   ▄█▀        ██     ██    ██    ▄██▄
 ▄██▄▄▄▄▄  ▄▄▄██▄▄▄  ██    ██   ▄█▀▀█▄
 ▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀  ▀▀    ▀▀  ▀▀▀  ▀▀▀

┌───────────────────────────────────────────────────┐
│ [Github] https://github.com/aceld                 │
│ [tutorial] https://www.kancloud.cn/aceld/zinx     │
└───────────────────────────────────────────────────┘
[Zinx] Version: V1.0, MaxConn: 3, MaxPacketSize: 4096
Add api msgID =  0
Add api msgID =  1
[START] Server name: zinx server Demo,listenner at IP: 127.0.0.1, Port 8999 is starting
Worker ID =  0  is started.
Worker ID =  1  is started.
Worker ID =  3  is started.
Worker ID =  2  is started.
Worker ID =  4  is started.
Worker ID =  5  is started.
Worker ID =  6  is started.
Worker ID =  7  is started.
Worker ID =  8  is started.
Worker ID =  9  is started.
start Zinx server   zinx server Demo  succ, now listenning...
[STOP] Zinx server , name  zinx server Demo
Clear All Connections successfully: conn num =  0
[START] Server name: zinx server Demo,listenner at IP: 127.0.0.1, Port 8999 is starting
Worker ID =  0  is started.
Worker ID =  4  is started.
Worker ID =  1  is started.
Worker ID =  2  is started.
Worker ID =  3  is started.
Worker ID =  5  is started.
Worker ID =  7  is started.
Worker ID =  8  is started.
Worker ID =  9  is started.
panic: listen tcp4 127.0.0.1:8999: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.

goroutine 34 [running]:
github.com/aceld/zinx/znet.(*Server).Start.func1()
        D:/GOPATH/pkg/mod/github.com/aceld/[email protected]/znet/server.go:88 +0x3ec
created by github.com/aceld/zinx/znet.(*Server).Start
        D:/GOPATH/pkg/mod/github.com/aceld/[email protected]/znet/server.go:74 +0x126
exit status 2

可能是因为Stop方法没有关闭listenner, 所以导致这个问题

我不确定我的修复建议是否可行:

  • 在Server里维护一个信号管道c,开一个新的goroutine不断accept连接,调用Stop()会向c中发信息, Start 携程负责阻塞等待这个信息, 并关闭listenner, 下面是伪代码
func (s *Server) Start() {
	go func() {
		tcpAddr, err := net.ResolveTCPAddr(s.TCPVersion, fmt.Sprintf("%v:%v", s.IP, s.Port))
		if err != nil {
			panic(err)
		}
		l, err := net.ListenTCP(s.TCPVersion, tcpAddr)
		if err != nil {
			panic(err)
		}
		log.Println("server started")

		go func() {
			for {
				var cid uint32 = 0
				c, err := l.AcceptTCP()
				if err != nil {
                                        if isListennerClosedErr(err) {
                                              log.Println("server had been stopped, accepter exiting")
                                              return
                                        }
					log.Println("failed to accept a connection, err:", err)
					continue
				}
				NewConnection(c, cid, s).Start()
				cid++
			}
		}()

		select {
		case <-s.StopChan:
			if err := l.Close(); err != nil {
				log.Println("failed to close tcp listenner, err:", err)
			}
		}

	}()
}

markity avatar Jul 15 '22 08:07 markity

#145

markity avatar Jul 16 '22 04:07 markity