2018-05-06 22:35:08 +08:00
|
|
|
// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://gitee.com/johng/gf.
|
|
|
|
|
|
|
|
package ghttp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"crypto/tls"
|
|
|
|
"gitee.com/johng/gf/g/os/glog"
|
2018-05-11 18:34:17 +08:00
|
|
|
"gitee.com/johng/gf/g/os/gproc"
|
2018-05-15 15:09:41 +08:00
|
|
|
"time"
|
2018-05-06 22:35:08 +08:00
|
|
|
)
|
|
|
|
|
2018-05-15 18:34:00 +08:00
|
|
|
const (
|
|
|
|
gGRACEFUL_SHUTDOWN_TIMEOUT = 10*time.Second // 优雅关闭链接时的超时时间
|
|
|
|
)
|
|
|
|
|
2018-05-06 22:35:08 +08:00
|
|
|
// 优雅的Web Server对象封装
|
|
|
|
type gracefulServer struct {
|
2018-05-08 18:41:29 +08:00
|
|
|
fd uintptr
|
|
|
|
addr string
|
2018-05-06 22:35:08 +08:00
|
|
|
httpServer *http.Server
|
2018-05-13 22:00:10 +08:00
|
|
|
rawln *net.TCPListener // 原始listener
|
|
|
|
listener net.Listener // 接口化封装的listener
|
2018-05-10 19:16:41 +08:00
|
|
|
isHttps bool
|
2018-05-06 22:35:08 +08:00
|
|
|
shutdownChan chan bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// 创建一个优雅的Http Server
|
2018-05-08 18:41:29 +08:00
|
|
|
func (s *Server) newGracefulServer(addr string, fd...int) *gracefulServer {
|
|
|
|
gs := &gracefulServer {
|
|
|
|
addr : addr,
|
2018-05-08 23:38:09 +08:00
|
|
|
httpServer : s.newHttpServer(addr),
|
2018-05-06 22:35:08 +08:00
|
|
|
shutdownChan : make(chan bool),
|
|
|
|
}
|
2018-05-08 18:41:29 +08:00
|
|
|
if len(fd) > 0 && fd[0] > 0 {
|
|
|
|
gs.fd = uintptr(fd[0])
|
|
|
|
}
|
|
|
|
return gs
|
2018-05-06 22:35:08 +08:00
|
|
|
}
|
|
|
|
|
2018-05-08 23:38:09 +08:00
|
|
|
// 生成一个底层的Web Server对象
|
|
|
|
func (s *Server) newHttpServer(addr string) *http.Server {
|
|
|
|
return &http.Server {
|
|
|
|
Addr : addr,
|
|
|
|
Handler : s.config.Handler,
|
|
|
|
ReadTimeout : s.config.ReadTimeout,
|
|
|
|
WriteTimeout : s.config.WriteTimeout,
|
|
|
|
IdleTimeout : s.config.IdleTimeout,
|
|
|
|
MaxHeaderBytes : s.config.MaxHeaderBytes,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-06 22:35:08 +08:00
|
|
|
// 执行HTTP监听
|
|
|
|
func (s *gracefulServer) ListenAndServe() error {
|
|
|
|
addr := s.httpServer.Addr
|
|
|
|
ln, err := s.getNetListener(addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-05-13 22:00:10 +08:00
|
|
|
//file, err := ln.(*net.TCPListener).File()
|
|
|
|
//if err != nil {
|
|
|
|
// return err
|
|
|
|
//}
|
|
|
|
//s.fd = file.Fd()
|
2018-05-06 22:35:08 +08:00
|
|
|
s.listener = ln
|
|
|
|
return s.doServe()
|
|
|
|
}
|
|
|
|
|
2018-05-13 22:00:10 +08:00
|
|
|
// 获得文件描述符
|
|
|
|
func (s *gracefulServer) Fd() uintptr {
|
2018-05-14 17:35:54 +08:00
|
|
|
if s.listener != nil {
|
|
|
|
file, err := s.listener.(*net.TCPListener).File()
|
|
|
|
if err == nil {
|
|
|
|
return file.Fd()
|
|
|
|
}
|
2018-05-13 22:00:10 +08:00
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2018-05-10 19:16:41 +08:00
|
|
|
// 设置自定义fd
|
|
|
|
func (s *gracefulServer) setFd(fd int) {
|
|
|
|
s.fd = uintptr(fd)
|
|
|
|
}
|
|
|
|
|
2018-05-06 22:35:08 +08:00
|
|
|
// 执行HTTPS监听
|
|
|
|
func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string) error {
|
|
|
|
addr := s.httpServer.Addr
|
|
|
|
config := &tls.Config{}
|
|
|
|
if s.httpServer.TLSConfig != nil {
|
|
|
|
*config = *s.httpServer.TLSConfig
|
|
|
|
}
|
|
|
|
if config.NextProtos == nil {
|
|
|
|
config.NextProtos = []string{"http/1.1"}
|
|
|
|
}
|
|
|
|
var err error
|
|
|
|
config.Certificates = make([]tls.Certificate, 1)
|
|
|
|
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ln, err := s.getNetListener(addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-05-13 22:00:10 +08:00
|
|
|
//file, err := ln.(*net.TCPListener).File()
|
|
|
|
//if err != nil {
|
|
|
|
// return err
|
|
|
|
//}
|
|
|
|
//s.fd = file.Fd()
|
2018-05-06 22:35:08 +08:00
|
|
|
s.listener = tls.NewListener(ln, config)
|
2018-05-10 19:16:41 +08:00
|
|
|
s.isHttps = true
|
2018-05-06 22:35:08 +08:00
|
|
|
return s.doServe()
|
|
|
|
}
|
|
|
|
|
2018-05-11 18:34:17 +08:00
|
|
|
// 获取服务协议字符串
|
|
|
|
func (s *gracefulServer) getProto() string {
|
|
|
|
proto := "http"
|
|
|
|
if s.isHttps {
|
|
|
|
proto = "https"
|
|
|
|
}
|
|
|
|
return proto
|
|
|
|
}
|
|
|
|
|
2018-05-06 22:35:08 +08:00
|
|
|
// 开始执行Web Server服务处理
|
|
|
|
func (s *gracefulServer) doServe() error {
|
2018-05-11 18:34:17 +08:00
|
|
|
glog.Printfln("%d: %s server started listening on [%s]", gproc.Pid(), s.getProto(), s.addr)
|
2018-05-06 22:35:08 +08:00
|
|
|
err := s.httpServer.Serve(s.listener)
|
|
|
|
<-s.shutdownChan
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 自定义的net.Listener
|
|
|
|
func (s *gracefulServer) getNetListener(addr string) (net.Listener, error) {
|
|
|
|
var ln net.Listener
|
|
|
|
var err error
|
2018-05-08 18:41:29 +08:00
|
|
|
if s.fd > 0 {
|
|
|
|
f := os.NewFile(s.fd, "")
|
2018-05-06 22:35:08 +08:00
|
|
|
ln, err = net.FileListener(f)
|
|
|
|
if err != nil {
|
2018-05-11 23:17:25 +08:00
|
|
|
err = fmt.Errorf("%d: net.FileListener error: %v", gproc.Pid(), err)
|
2018-05-06 22:35:08 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ln, err = net.Listen("tcp", addr)
|
|
|
|
if err != nil {
|
2018-05-11 23:17:25 +08:00
|
|
|
err = fmt.Errorf("%d: net.Listen error: %v", gproc.Pid(), err)
|
2018-05-06 22:35:08 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ln, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 执行请求优雅关闭
|
|
|
|
func (s *gracefulServer) shutdown() {
|
2018-05-15 18:34:00 +08:00
|
|
|
if err := s.httpServer.Shutdown(context.Background()); err != nil {
|
2018-05-15 15:09:41 +08:00
|
|
|
glog.Errorfln("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
2018-05-06 22:35:08 +08:00
|
|
|
} else {
|
2018-05-15 18:34:00 +08:00
|
|
|
//glog.Printfln("%d: %s server [%s] shutdown smoothly", gproc.Pid(), s.getProto(), s.addr)
|
2018-05-06 22:35:08 +08:00
|
|
|
s.shutdownChan <- true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-13 00:17:12 +08:00
|
|
|
// 执行请求强制关闭
|
|
|
|
func (s *gracefulServer) close() {
|
|
|
|
if err := s.httpServer.Close(); err != nil {
|
2018-05-13 14:04:37 +08:00
|
|
|
glog.Errorfln("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
2018-05-13 00:17:12 +08:00
|
|
|
} else {
|
2018-05-15 18:34:00 +08:00
|
|
|
//glog.Printfln("%d: %s server [%s] closed smoothly", gproc.Pid(), s.getProto(), s.addr)
|
2018-05-13 00:17:12 +08:00
|
|
|
s.shutdownChan <- true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|