func (serv *Server) handleClose(conn int, req *Frame) {
	switch {
	case req.closeCode == 0:
		req.closeCode = StatusBadRequest
	case req.closeCode < StatusNormal:
		req.closeCode = StatusBadRequest
	case req.closeCode == 1004:
		req.closeCode = StatusBadRequest
	case req.closeCode == 1005:
		req.closeCode = StatusBadRequest
	case req.closeCode == 1006:
		req.closeCode = StatusBadRequest
	case req.closeCode >= 1015 && req.closeCode <= 2999:
		req.closeCode = StatusBadRequest
	case req.closeCode >= 3000 && req.closeCode <= 3999:
	case req.closeCode >= 4000 && req.closeCode <= 4999:
	}
	if len(req.payload) >= 2 {
		req.payload = req.payload[2:]
		if !utf8.Valid(req.payload) {
			req.closeCode = StatusBadRequest
		}
	}
	packet := NewFrameClose(false, req.closeCode, req.payload)
	if debug.Value >= 3 {
		fmt.Printf("websocket: Server.handleClose: req: %+v\n", req)
	}
	err := Send(conn, packet)
	if err != nil {
		log.Println("websocket: server.handleClose: Send: " + err.Error())
	}
	serv.ClientRemove(conn)
}
handleClose request from client.
package websocket
import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"time"
	"unicode/utf8"
	"golang.org/x/sys/unix"
	libbytes "github.com/shuLhan/share/lib/bytes"
	"github.com/shuLhan/share/lib/debug"
	libnet "github.com/shuLhan/share/lib/net"
)
const (
	_maxQueue = 128
	_resUpgradeOK = "HTTP/1.1 101 Switching Protocols\r\n" +
		"Upgrade: websocket\r\n" +
		"Connection: Upgrade\r\n" +
		"Sec-Websocket-Accept: "
	_resStatusOK = "HTTP/1.1 200 OK\r\n" +
		"Content-Type: %s\r\n" +
		"Content-Length: %d\r\n" +
		"\r\n" +
		"%s"
)
type Server struct {
	Clients *ClientManager
	Options *ServerOptions
	sock      int
	chUpgrade chan int
	running   chan struct{}
	poll libnet.Poll
	routes *rootRoute
	handlePong HandlerFrameFn
	allowRsv1 bool
	allowRsv2 bool
	allowRsv3 bool
}
func NewServer(opts *ServerOptions) (serv *Server) {
	if opts == nil {
		opts = &ServerOptions{}
	}
	serv = &Server{
		Options: opts,
		Clients: newClientManager(),
		routes:  newRootRoute(),
		running: make(chan struct{}, 1),
	}
	opts.init()
	if opts.HandleBin == nil {
		opts.HandleBin = serv.handleBin
	}
	if opts.HandleText == nil {
		opts.HandleText = serv.handleText
	}
	return serv
}
func (serv *Server) AllowReservedBits(one, two, three bool) {
	serv.allowRsv1 = one
	serv.allowRsv2 = two
	serv.allowRsv3 = three
}
func (serv *Server) createSockServer() (err error) {
	serv.sock, err = unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
	if err != nil {
		return
	}
	err = unix.SetsockoptInt(serv.sock, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
	if err != nil {
		return
	}
	host, strPort, err := net.SplitHostPort(serv.Options.Address)
	if err != nil {
		return
	}
	port, err := strconv.Atoi(strPort)
	if err != nil {
		return
	}
	addr := unix.SockaddrInet4{Port: port}
	copy(addr.Addr[:], net.ParseIP(host).To4())
	err = unix.Bind(serv.sock, &addr)
	if err != nil {
		return
	}
	err = unix.Listen(serv.sock, _maxQueue)
	return
}
func (serv *Server) RegisterTextHandler(
	method, target string, handler RouteHandler,
) (err error) {
	if len(method) == 0 || len(target) == 0 || handler == nil {
		return
	}
	err = serv.routes.add(method, target, handler)
	return
}
func (serv *Server) handleError(conn int, code int, msg string) {
	rspBody := "HTTP/1.1 " + strconv.Itoa(code) + " " + msg + "\r\n\r\n"
	err := Send(conn, []byte(rspBody))
	if err != nil {
		log.Println("websocket: server.handleError: " + err.Error())
	}
	unix.Close(conn)
}
func (serv *Server) handleUpgrade(hs *Handshake) (
	ctx context.Context, key []byte, err error,
) {
	err = hs.parse()
	if err == nil {
		key = libbytes.Copy(hs.Key)
		if serv.Options.HandleAuth != nil {
			ctx, err = serv.Options.HandleAuth(hs)
		}
	}
	hs.reset(nil)
	_handshakePool.Put(hs)
	return ctx, key, err
}
func (serv *Server) clientAdd(ctx context.Context, conn int) (err error) {
	err = serv.poll.RegisterRead(conn)
	if err != nil {
		return fmt.Errorf("websocket: Server.clientAdd: " + err.Error())
	}
	if ctx != nil {
		serv.Clients.add(ctx, conn)
		if serv.Options.HandleClientAdd != nil {
			go serv.Options.HandleClientAdd(ctx, conn)
		}
	}
	return nil
}
func (serv *Server) ClientRemove(conn int) {
	ctx := serv.Clients.Context(conn)
	if ctx != nil && serv.Options.HandleClientRemove != nil {
		serv.Options.HandleClientRemove(ctx, conn)
	}
	serv.Clients.remove(conn)
	err := serv.poll.UnregisterRead(conn)
	if err != nil {
		log.Println("websocket: server.ClientRemove: " + err.Error())
	}
	err = unix.Close(conn)
	if err != nil {
		log.Println("websocket: server.ClientRemove: " + err.Error())
	}
}
func (serv *Server) upgrader() {
	for conn := range serv.chUpgrade {
		packet, err := Recv(conn)
		if err != nil {
			log.Println("websocket: server.upgrader: " + err.Error())
			unix.Close(conn)
			continue
		}
		if len(packet) == 0 {
			unix.Close(conn)
			continue
		}
		hs, err := newHandshake(packet)
		if err != nil {
			serv.handleError(conn, http.StatusBadRequest, err.Error())
			continue
		}
		if hs.URL.Path == serv.Options.StatusPath {
			serv.handleStatus(conn)
			continue
		}
		if hs.URL.Path != serv.Options.ConnectPath {
			serv.handleError(conn, http.StatusNotFound,
				"unknown path")
			continue
		}
		ctx, key, err := serv.handleUpgrade(hs)
		if err != nil {
			serv.handleError(conn, http.StatusBadRequest, err.Error())
			continue
		}
		wsAccept := generateHandshakeAccept(key)
		httpRes := _resUpgradeOK + wsAccept + "\r\n\r\n"
		err = Send(conn, []byte(httpRes))
		if err != nil {
			log.Println("websocket: server.upgrader: Send: ",
				err.Error())
			unix.Close(conn)
			continue
		}
		if ctx == nil {
			ctx = context.Background()
		}
		err = serv.clientAdd(ctx, conn)
		if err != nil {
			log.Println("websocket: server.upgrader: clientAdd: ",
				err.Error())
			unix.Close(conn)
		}
	}
}
func (serv *Server) handleFragment(conn int, req *Frame) (isInvalid bool) {
	frames, ok := serv.Clients.getFrames(conn)
	if debug.Value >= 3 {
		fmt.Printf("websocket: Server.handleFragment: frame: {fin:%d opcode:%d masked:%d len:%d, payload.len:%d}\n",
			req.fin, req.opcode, req.masked, req.len,
			len(req.payload))
	}
	if frames == nil {
		if req.opcode == OpcodeCont {
			serv.handleBadRequest(conn)
			return true
		}
	} else if req.opcode != OpcodeCont {
		serv.handleBadRequest(conn)
		return true
	}
	if req.fin == 0 {
		if uint64(len(req.payload)) < req.len {
			serv.Clients.setFrame(conn, req)
		} else {
			if frames == nil {
				frames = new(Frames)
			}
			frames.Append(req)
			serv.Clients.setFrame(conn, nil)
			serv.Clients.setFrames(conn, frames)
		}
		return false
	}
	if !ok && uint64(len(req.payload)) < req.len {
		serv.Clients.setFrame(conn, req)
		return false
	}
	frame := serv.Clients.finFrames(conn, req)
	if frame.opcode == OpcodeText {
		if !utf8.Valid(frame.payload) {
			serv.handleInvalidData(conn)
			return true
		}
		go serv.Options.HandleText(conn, frame.payload)
	} else {
		go serv.Options.HandleBin(conn, frame.payload)
	}
	return false
}
func (serv *Server) handleFrame(conn int, frame *Frame) (isClosing bool) {
	if !frame.isValid(true, serv.allowRsv1, serv.allowRsv2, serv.allowRsv3) {
		serv.handleBadRequest(conn)
		return true
	}
	switch frame.opcode {
	case OpcodeCont, OpcodeText, OpcodeBin:
		isInvalid := serv.handleFragment(conn, frame)
		if isInvalid {
			isClosing = true
		}
	case OpcodeDataRsv3, OpcodeDataRsv4, OpcodeDataRsv5, OpcodeDataRsv6,
		OpcodeDataRsv7:
		serv.handleBadRequest(conn)
		isClosing = true
	case OpcodeClose:
		serv.handleClose(conn, frame)
		isClosing = true
	case OpcodePing:
		serv.handlePing(conn, frame)
	case OpcodePong:
		if serv.handlePong != nil {
			go serv.handlePong(conn, frame)
		}
	case OpcodeControlRsvB, OpcodeControlRsvC, OpcodeControlRsvD,
		OpcodeControlRsvE, OpcodeControlRsvF:
		if serv.Options.HandleRsvControl != nil {
			serv.Options.HandleRsvControl(conn, frame)
		} else {
			serv.handleClose(conn, frame)
			isClosing = true
		}
	}
	return isClosing
}
func (serv *Server) handleText(conn int, payload []byte) {
	var (
		handler RouteHandler
		err     error
		ctx     context.Context
		req     *Request
	)
	res := _resPool.Get().(*Response)
	res.reset()
	ctx, ok := serv.Clients.ctx[conn]
	if !ok {
		err = errors.New("client context not found")
		res.Code = http.StatusInternalServerError
		res.Message = err.Error()
		goto out
	}
	req = _reqPool.Get().(*Request)
	req.reset()
	err = json.Unmarshal(payload, req)
	if err != nil {
		res.Code = http.StatusBadRequest
		res.Message = err.Error()
		goto out
	}
	handler, err = req.unpack(serv.routes)
	if err != nil {
		res.Code = http.StatusBadRequest
		res.Message = req.Target
		goto out
	}
	if handler == nil {
		res.Code = http.StatusNotFound
		res.Message = req.Method + " " + req.Target
		goto out
	}
	req.Conn = conn
	*res = handler(ctx, req)
out:
	if req != nil {
		res.ID = req.ID
		_reqPool.Put(req)
	}
	err = serv.sendResponse(conn, res)
	if err != nil {
		serv.ClientRemove(conn)
	}
	_resPool.Put(res)
}
func (serv *Server) handleBin(conn int, payload []byte) {}
func (serv *Server) handleStatus(conn int) {
	var (
		contentType string
		data        []byte
	)
	if serv.Options.HandleStatus == nil {
		contentType = "text/plain"
		data = []byte("OK")
	} else {
		contentType, data = serv.Options.HandleStatus()
	}
	res := fmt.Sprintf(_resStatusOK, contentType, len(data), data)
	err := Send(conn, []byte(res))
	if err != nil {
		log.Println("websocket /health: Send: ", err.Error())
	}
	unix.Close(conn)
}