func (c *Conn) Stop(mode int) {
	c.once.Do(func() {
		if mode == StopImmediately {
			atomic.StoreInt32(&c.state, connStateStopped)
			close(c.closed)
			if c.RawConn != nil {
				err := c.RawConn.Close()
				if err != nil {
					zap.S().Warnf("[%s] Failed to close the connection properly: %v", c.RawConn.RemoteAddr(), err)
				}
			}
		} else {
			atomic.StoreInt32(&c.state, connStateStopping)
			close(c.closed)
			if mode == StopGracefullyAndWait {
				c.wg.Wait()
			}
		}
	})
}
Stop stops the conn.
package internal
import (
	"bufio"
	"encoding/binary"
	"io"
	"net"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"github.com/pkg/errors"
	"go.uber.org/zap"
)
const (
	DefaultRecvBufSize     = 4 << 10           
	DefaultSendQueueLen    = 1 << 7            
	maxTemporaryErrorDelay = 1 * time.Second   
	handshakeTimeout       = 30 * time.Second  
	maxPayloadLength       = 2 << 20           
	magic                  = 0x12345678        
	sizeLength             = 4                 
	magicLength            = 4                 
)
const (
	StopImmediately       = iota  
	StopGracefullyAndWait         
)
const (
	connStateInitial int32 = iota
	connStateNormal
	connStateStopping
	connStateStopped
)
type Handler interface {
	OnAccept(*Conn)           
	OnConnect(*Conn)          
	OnReceive(*Conn, []byte)  
	OnClose(*Conn)            
}
type Options struct {
	Handler         Handler
	RecvBufSize     int            
	SendQueueLen    int            
	AsyncWrite      bool           
	NoDelay         bool           
	KeepAlive       bool           
	KeepAlivePeriod time.Duration  
	ReadDeadline    time.Duration  
	WriteDeadline   time.Duration  
}
func NewOptions(h Handler) *Options {
	if h == nil {
		panic("nil handler is not allowed")
	}
	return &Options{
		Handler:      h,
		RecvBufSize:  DefaultRecvBufSize,
		SendQueueLen: DefaultSendQueueLen,
		AsyncWrite:   true,
		NoDelay:      true,
		KeepAlive:    false,
	}
}
type Conn struct {
	sync.Mutex
	Opts        *Options
	RawConn     net.Conn
	UserData    interface{}
	sendBufList chan []byte
	closed      chan struct{}
	state       int32
	wg          sync.WaitGroup
	once        sync.Once
	SendDropped uint32
	sendBytes   uint64
	recvBytes   uint64
	dropped     uint32
}
func NewConn(opts *Options) *Conn {
	if opts.RecvBufSize <= 0 {
		zap.S().Warnf("Invalid receiving buffer size %d, using default %d", opts.RecvBufSize, DefaultRecvBufSize)
		opts.RecvBufSize = DefaultRecvBufSize
	}
	if opts.SendQueueLen <= 0 {
		zap.S().Warnf("Invalid sending queue length %d, using default %d", opts.SendQueueLen, DefaultSendQueueLen)
		opts.SendQueueLen = DefaultSendQueueLen
	}
	c := &Conn{
		Opts:        opts,
		sendBufList: make(chan []byte, opts.SendQueueLen),
		closed:      make(chan struct{}),
		state:       connStateInitial,
	}
	return c
}
func (c *Conn) String() string {
	s := atomic.LoadInt32(&c.state)
	var sc rune
	switch s {
	case connStateInitial:
		sc = '>'
	case connStateNormal:
		sc = '-'
	case connStateStopping:
		sc = '|'
	case connStateStopped:
		sc = 'X'
	}
	la := "N/A"
	ra := "N/A"
	if c.RawConn != nil {
		la = c.RawConn.LocalAddr().String()
		ra = c.RawConn.RemoteAddr().String()
	}
	sb := strings.Builder{}
	sb.WriteString(la)
	sb.WriteRune('-')
	sb.WriteRune(sc)
	sb.WriteRune('>')
	sb.WriteString(ra)
	return sb.String()
}
func (c *Conn) SendBytes() uint64 {
	return atomic.LoadUint64(&c.sendBytes)
}
func (c *Conn) RecvBytes() uint64 {
	return atomic.LoadUint64(&c.recvBytes)
}
func (c *Conn) DroppedPacket() uint32 {
	return atomic.LoadUint32(&c.dropped)
}