什么是框架
把变化交给用户,把不变留给自己,面向接口编程
案例
tcpsever实现
监听类型
监听地址
客户端连接处理
将三部分作为参数传递
srv := tcpserver.NewServer(
tcpserver.Network("tcp"),
tcpserver.Address(":8080"),
tcpserver.Handler(MyHandler),
)
tcpsever.handler传入是函数对象,如此定义
type connectionHandler func(context.context,net.conect)error
函数签名中最重要是net.conn参数,作为独立参数直接定义,上下文参数context,上下文可以传递各种变量信号与上层中断信号。
最后是启动与关闭函数
func (srv *Server) Serve(ctx context.Context) error {
//TODO
return nil
}
func (srv *Server) Close() {
//TODO
}
graceful shutdown功能实现
- 关闭所有监听
- 关闭所有闲置连接
- 等待运行连接处理完成
- 上下文超时信号处理
缺点是有协程没有处理完就会一直处理,通过超时机制来规避
close函数提供此功能,收到信号关闭监听在等待所有客户端连接完成
//Close tcpserver waiting all connections finished
func (srv *Server) Close() {
//触发关闭信号
close(srv.closed)
//等待客户端连完成
srv.wgroup.Wait()
}
//Serve tcpserver serving
func (srv *Server) Serve(ctx context.Context) error {
ln, err := net.Listen(srv.network, srv.address)//开启监听
...
for {
select {
case <-ctx.Done():
return ctx.Err()
case <-srv.closed: //收到关闭信号
log.Println("tcpserver is closing ...")
return ln.Close()//关闭监听
...
}
...
}
由于serve.Serve函数在for循环中一直阻塞在Accept()函数处,所以原代码中使用close chan的方式触发关闭过程失败。新版本直接通过关闭Listener的方式触发关闭。
//Close tcpserver waiting all connections finished
func (srv *Server) Close() {
//关闭监听,触发关闭信号
srv.Listener.Close()
//等待客户端连完成
srv.wgroup.Wait()
}