├── config_json.go ├── func_fmt.go ├── parser_test.go ├── container_test.go ├── parser_msgpack.go ├── parser_json.go ├── parser_pb.go ├── func_go.go ├── math.go ├── error.go ├── array_map.go ├── model_redis.go ├── func_strings.go ├── init.go ├── container.go ├── func_compress.go ├── parser_cmd.go ├── collision.go ├── config_csv.go ├── func_file.go ├── parser.go ├── time.go ├── func_net.go ├── msgque_msg.go ├── msgque_udp.go ├── db_redis.go ├── msgque_ws.go ├── log.go ├── msgque_tcp.go ├── README.md ├── func.go └── msgque.go /config_json.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | ) 7 | 8 | func ReadConfigFromJson(path string, v interface{}) error { 9 | data, err := ioutil.ReadFile(path) 10 | if err != nil { 11 | return ErrFileRead 12 | } 13 | 14 | err = json.Unmarshal(data, v) 15 | if err != nil { 16 | return ErrJsonUnPack 17 | } 18 | return nil 19 | } 20 | -------------------------------------------------------------------------------- /func_fmt.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Print(a ...interface{}) (int, error) { 8 | return fmt.Print(a...) 9 | } 10 | func Println(a ...interface{}) (int, error) { 11 | return fmt.Println(a...) 12 | } 13 | func Printf(format string, a ...interface{}) (int, error) { 14 | return fmt.Printf(format, a...) 15 | } 16 | func Sprintf(format string, a ...interface{}) string { 17 | return fmt.Sprintf(format, a...) 18 | } 19 | -------------------------------------------------------------------------------- /parser_test.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | type GetGamerLevel struct { 8 | Get string `match:"k"` 9 | Gamer int 10 | Level int `match:"k"` 11 | } 12 | 13 | type GetGamerRmb struct { 14 | Get string `match:"k"` 15 | Gamer int 16 | Rmb int `match:"k"` 17 | } 18 | 19 | func Test_CmdParser(t *testing.T) { 20 | pm := Parser{Type: ParserTypeCmd} 21 | pm.RegisterMsg(&GetGamerLevel{}, nil) 22 | 23 | p := pm.Get() 24 | m, _ := p.ParseC2S(NewStrMsg("get gamer 1 level")) 25 | Printf("%#v\n", m.C2S().(*GetGamerLevel)) 26 | 27 | Println(m.C2SString()) 28 | } 29 | -------------------------------------------------------------------------------- /container_test.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_MinHeap(t *testing.T) { 8 | mh := NewMinHeap() 9 | for i := 10000; i > 0; i-- { 10 | mh.Push(i, i) 11 | } 12 | m, p := mh.GetMin() 13 | top := mh.Top() 14 | Printf("min : %v %v %v\n", m, p, top) 15 | for i := 0; i < 10; i++ { 16 | x := mh.Pop() 17 | Printf("%v ", x) 18 | } 19 | 20 | Println("") 21 | 22 | mh.Push(1, 554654) 23 | mh.Push(1, 333) 24 | i := mh.Pop() 25 | Println(i, mh.Len()) 26 | 27 | mh.Push(0, 19384) 28 | i = mh.Pop() 29 | Println(i, mh.Len()) 30 | } 31 | 32 | func Test_MaxHeap(t *testing.T) { 33 | mh := NewMaxHeap() 34 | for i := 10000; i > 0; i-- { 35 | mh.Push(i, i) 36 | } 37 | m, p := mh.GetMin() 38 | top := mh.Top() 39 | Printf("max : %v %v %v\n", m, p, top) 40 | for i := 0; i < 10; i++ { 41 | x := mh.Pop() 42 | Printf("%v ", x) 43 | } 44 | 45 | Println("") 46 | 47 | mh.Push(1, 554654) 48 | mh.Push(1, 333) 49 | i := mh.Pop() 50 | Println(i, mh.Len()) 51 | 52 | mh.Push(0, 19384) 53 | i = mh.Pop() 54 | Println(i, mh.Len()) 55 | } 56 | -------------------------------------------------------------------------------- /parser_msgpack.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "github.com/vmihailenco/msgpack" 5 | ) 6 | 7 | type MsgpackParser struct { 8 | *Parser 9 | } 10 | 11 | func (r *MsgpackParser) ParseC2S(msg *Message) (IMsgParser, error) { 12 | if msg == nil { 13 | return nil, ErrMsgPackUnPack 14 | } 15 | 16 | if msg.Head == nil { 17 | if len(msg.Data) == 0 { 18 | return nil, ErrMsgPackUnPack 19 | } 20 | for _, p := range r.typMap { 21 | if p.C2S() != nil { 22 | err := MsgPackUnPack(msg.Data, p.C2S()) 23 | if err != nil { 24 | continue 25 | } 26 | p.parser = r 27 | return &p, nil 28 | } 29 | } 30 | } else if p, ok := r.msgMap[msg.Head.CmdAct()]; ok { 31 | if p.C2S() != nil { 32 | if len(msg.Data) > 0 { 33 | err := MsgPackUnPack(msg.Data, p.C2S()) 34 | if err != nil { 35 | return nil, err 36 | } 37 | } 38 | p.parser = r 39 | return &p, nil 40 | } 41 | } 42 | 43 | return nil, ErrMsgPackUnPack 44 | } 45 | 46 | func (r *MsgpackParser) PackMsg(v interface{}) []byte { 47 | data, _ := MsgPackPack(v) 48 | return data 49 | } 50 | 51 | func (r *MsgpackParser) GetRemindMsg(err error, t MsgType) *Message { 52 | if t == MsgTypeMsg { 53 | return NewErrMsg(err) 54 | } else { 55 | return NewStrMsg(err.Error() + "\n") 56 | } 57 | } 58 | 59 | func MsgPackUnPack(data []byte, msg interface{}) error { 60 | err := msgpack.Unmarshal(data, msg) 61 | return err 62 | } 63 | 64 | func MsgPackPack(msg interface{}) ([]byte, error) { 65 | data, err := msgpack.Marshal(msg) 66 | return data, err 67 | } 68 | -------------------------------------------------------------------------------- /parser_json.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import "encoding/json" 4 | 5 | type JsonParser struct { 6 | *Parser 7 | } 8 | 9 | func (r *JsonParser) ParseC2S(msg *Message) (IMsgParser, error) { 10 | if msg == nil { 11 | return nil, ErrJsonUnPack 12 | } 13 | 14 | if msg.Head == nil { 15 | if len(msg.Data) == 0 { 16 | return nil, ErrJsonUnPack 17 | } 18 | for _, p := range r.typMap { 19 | if p.C2S() != nil { 20 | err := JsonUnPack(msg.Data, p.C2S()) 21 | if err != nil { 22 | continue 23 | } 24 | p.parser = r 25 | return &p, nil 26 | } 27 | } 28 | } else if p, ok := r.msgMap[msg.Head.CmdAct()]; ok { 29 | if p.C2S() != nil { 30 | if len(msg.Data) > 0 { 31 | err := JsonUnPack(msg.Data, p.C2S()) 32 | if err != nil { 33 | return nil, err 34 | } 35 | } 36 | p.parser = r 37 | return &p, nil 38 | } 39 | } 40 | 41 | return nil, ErrJsonUnPack 42 | } 43 | 44 | func (r *JsonParser) PackMsg(v interface{}) []byte { 45 | data, _ := JsonPack(v) 46 | return data 47 | } 48 | 49 | func (r *JsonParser) GetRemindMsg(err error, t MsgType) *Message { 50 | if t == MsgTypeMsg { 51 | return NewErrMsg(err) 52 | } else { 53 | return NewStrMsg(err.Error() + "\n") 54 | } 55 | } 56 | 57 | func JsonUnPack(data []byte, msg interface{}) error { 58 | if data == nil || msg == nil { 59 | return ErrJsonUnPack 60 | } 61 | 62 | err := json.Unmarshal(data, msg) 63 | if err != nil { 64 | return ErrJsonUnPack 65 | } 66 | return nil 67 | } 68 | 69 | func JsonPack(msg interface{}) ([]byte, error) { 70 | if msg == nil { 71 | return nil, ErrJsonPack 72 | } 73 | 74 | data, err := json.Marshal(msg) 75 | if err != nil { 76 | LogInfo("") 77 | return nil, ErrJsonPack 78 | } 79 | 80 | return data, nil 81 | } 82 | -------------------------------------------------------------------------------- /parser_pb.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | ) 6 | 7 | type PBParser struct { 8 | *Parser 9 | } 10 | 11 | func (r *PBParser) ParseC2S(msg *Message) (IMsgParser, error) { 12 | if msg == nil { 13 | return nil, ErrPBUnPack 14 | } 15 | 16 | if msg.Head == nil { 17 | if len(msg.Data) == 0 { 18 | return nil, ErrPBUnPack 19 | } 20 | for _, p := range r.typMap { 21 | if p.C2S() != nil { 22 | err := PBUnPack(msg.Data, p.C2S()) 23 | if err != nil { 24 | continue 25 | } 26 | p.parser = r 27 | return &p, nil 28 | } 29 | } 30 | } else if p, ok := r.msgMap[msg.Head.CmdAct()]; ok { 31 | if p.C2S() != nil { 32 | if len(msg.Data) > 0 { 33 | err := PBUnPack(msg.Data, p.C2S()) 34 | if err != nil { 35 | return nil, err 36 | } 37 | } 38 | p.parser = r 39 | return &p, nil 40 | } 41 | } 42 | 43 | return nil, ErrPBUnPack 44 | } 45 | 46 | func (r *PBParser) PackMsg(v interface{}) []byte { 47 | data, _ := PBPack(v) 48 | return data 49 | } 50 | 51 | func (r *PBParser) GetRemindMsg(err error, t MsgType) *Message { 52 | if t == MsgTypeMsg { 53 | return NewErrMsg(err) 54 | } else { 55 | return NewStrMsg(err.Error() + "\n") 56 | } 57 | } 58 | 59 | func PBUnPack(data []byte, msg interface{}) error { 60 | if data == nil || msg == nil { 61 | return ErrPBUnPack 62 | } 63 | 64 | err := proto.Unmarshal(data, msg.(proto.Message)) 65 | if err != nil { 66 | return ErrPBUnPack 67 | } 68 | return nil 69 | } 70 | 71 | func PBPack(msg interface{}) ([]byte, error) { 72 | if msg == nil { 73 | return nil, ErrPBPack 74 | } 75 | 76 | data, err := proto.Marshal(msg.(proto.Message)) 77 | if err != nil { 78 | LogInfo("") 79 | } 80 | 81 | return data, nil 82 | } 83 | -------------------------------------------------------------------------------- /func_go.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "sync/atomic" 5 | ) 6 | 7 | func Go(fn func()) { 8 | pc := Config.PoolSize + 1 9 | select { 10 | case poolChan <- fn: 11 | return 12 | default: 13 | pc = atomic.AddInt32(&poolGoCount, 1) 14 | if pc > Config.PoolSize { 15 | atomic.AddInt32(&poolGoCount, -1) 16 | } 17 | } 18 | 19 | waitAll.Add(1) 20 | var debugStr string 21 | id := atomic.AddUint32(&goid, 1) 22 | c := atomic.AddInt32(&gocount, 1) 23 | if DefLog.Level() <= LogLevelDebug { 24 | debugStr = LogSimpleStack() 25 | LogTrace("goroutine start id:%d count:%d from:%s", id, c, debugStr) 26 | } 27 | go func() { 28 | Try(fn, nil) 29 | for pc <= Config.PoolSize { 30 | select { 31 | case <-stopChanForGo: 32 | pc = Config.PoolSize + 1 33 | case nfn := <-poolChan: 34 | Try(nfn, nil) 35 | } 36 | } 37 | 38 | waitAll.Done() 39 | c = atomic.AddInt32(&gocount, -1) 40 | 41 | if DefLog.Level() <= LogLevelDebug { 42 | LogTrace("goroutine end id:%d count:%d from:%s", id, c, debugStr) 43 | } 44 | }() 45 | } 46 | 47 | func Go2(fn func(cstop chan struct{})) { 48 | Go(func() { 49 | fn(stopChanForGo) 50 | }) 51 | } 52 | 53 | func GoArgs(fn func(...interface{}), args ...interface{}) { 54 | Go(func() { 55 | fn(args...) 56 | }) 57 | } 58 | 59 | func goForRedis(fn func()) { 60 | waitAllForRedis.Add(1) 61 | var debugStr string 62 | id := atomic.AddUint32(&goid, 1) 63 | c := atomic.AddInt32(&gocount, 1) 64 | if DefLog.Level() <= LogLevelDebug { 65 | debugStr = LogSimpleStack() 66 | LogTrace("goroutine start id:%d count:%d from:%s", id, c, debugStr) 67 | } 68 | go func() { 69 | Try(fn, nil) 70 | waitAllForRedis.Done() 71 | c = atomic.AddInt32(&gocount, -1) 72 | 73 | if DefLog.Level() <= LogLevelDebug { 74 | LogTrace("goroutine end id:%d count:%d from:%s", id, c, debugStr) 75 | } 76 | }() 77 | } 78 | 79 | func goForLog(fn func(cstop chan struct{})) bool { 80 | if IsStop() { 81 | return false 82 | } 83 | waitAllForLog.Add(1) 84 | 85 | go func() { 86 | fn(stopChanForLog) 87 | waitAllForLog.Done() 88 | }() 89 | return true 90 | } 91 | -------------------------------------------------------------------------------- /math.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | ) 7 | 8 | //x^y 9 | func Pow(x, y float64) float64 { 10 | return math.Pow(x, y) 11 | } 12 | 13 | //返回x的二次方根 14 | func Sqrt(x float64) float64 { 15 | return math.Sqrt(x) 16 | } 17 | 18 | //取0-number区间的随机值 19 | func RandNumber(number int) int { 20 | if number == 0 { 21 | return 0 22 | } 23 | return rand.Intn(number) 24 | } 25 | 26 | //min和max之间的随机数 27 | func RandNumBetween(min, max int) int { 28 | if min == max { 29 | return min 30 | } 31 | if min > max { 32 | min, max = max, min 33 | } 34 | return rand.Intn(max-min) + min 35 | } 36 | 37 | //正态分布:根据标准差和期望生成不同的正态分布值,sd标准差,mean期望 38 | func RandNorm64(sd, mean int32) float64 { 39 | return rand.NormFloat64()*float64(sd) + float64(mean) 40 | } 41 | 42 | //正态分布,在一定范围内 43 | func RandNormInt32(min, max, sd, mean int32) int32 { 44 | result := int32(Atoi(RoundStr("%0.0f", RandNorm64(sd, mean)))) 45 | if result < min { 46 | return min 47 | } 48 | if result > max { 49 | return max 50 | } 51 | return result 52 | } 53 | 54 | //四舍五入保留n位小数,如保留整数"%.0f",保留3位小数"%.3f"...保留n位小数"%.nf" 55 | func RoundStr(format string, decimal float64) string { 56 | return Sprintf(format, decimal) 57 | } 58 | 59 | //四舍五入保留n位小数 60 | func Round(decimal float64, w int) float32 { 61 | format := "%." + Itoa(w) + "f" 62 | return Atof(Sprintf(format, decimal)) 63 | } 64 | 65 | //四舍五入保留n位小数 66 | func Round64(decimal float64, w int) float64 { 67 | format := "%." + Itoa(w) + "f" 68 | return Atof64(Sprintf(format, decimal)) 69 | } 70 | 71 | //Log10为底x的对数 72 | func Log10(x float64) float64 { 73 | return math.Log10(x) 74 | } 75 | 76 | //abs 77 | func Abs(x float64) float64 { 78 | return math.Abs(x) 79 | } 80 | 81 | //int32 82 | func MaxInt32() int32 { 83 | return math.MaxInt32 84 | } 85 | 86 | // 两个数的较大值 87 | func Max(x, y int32) int32 { 88 | if x > y { 89 | return x 90 | } 91 | 92 | return y 93 | } 94 | 95 | // 两个数的较小值 96 | func Min(x, y int32) int32 { 97 | if x > y { 98 | return y 99 | } 100 | 101 | return x 102 | } 103 | 104 | //int32取绝对值 105 | func Int32Abs(x int32) int32 { 106 | if x < 0 { 107 | return -x 108 | } 109 | return x 110 | } 111 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import "sync" 4 | 5 | type Error struct { 6 | Id uint16 7 | Str string 8 | } 9 | 10 | func (r *Error) Error() string { 11 | return r.Str 12 | } 13 | 14 | var idErrMap = sync.Map{} 15 | var errIdMap = sync.Map{} 16 | 17 | func NewError(str string, id uint16) *Error { 18 | err := &Error{id, str} 19 | idErrMap.Store(id, err) 20 | errIdMap.Store(err, id) 21 | return err 22 | } 23 | 24 | var ( 25 | ErrOk = NewError("正确", 0) 26 | ErrDBErr = NewError("数据库错误", 1) 27 | ErrProtoPack = NewError("协议解析错误", 2) 28 | ErrProtoUnPack = NewError("协议打包错误", 3) 29 | ErrMsgPackPack = NewError("msgpack打包错误", 4) 30 | ErrMsgPackUnPack = NewError("msgpack解析错误", 5) 31 | ErrPBPack = NewError("pb打包错误", 6) 32 | ErrPBUnPack = NewError("pb解析错误", 7) 33 | ErrJsonPack = NewError("json打包错误", 8) 34 | ErrJsonUnPack = NewError("json解析错误", 9) 35 | ErrCmdUnPack = NewError("cmd解析错误", 10) 36 | ErrMsgLenTooLong = NewError("数据过长", 11) 37 | ErrMsgLenTooShort = NewError("数据过短", 12) 38 | ErrHttpRequest = NewError("http请求错误", 13) 39 | ErrCSVParse = NewError("csv解析错误", 14) 40 | ErrGobPack = NewError("gob打包错误", 15) 41 | ErrGobUnPack = NewError("gob解析错误", 16) 42 | ErrServePanic = NewError("服务器内部错误", 17) 43 | ErrNeedIntraNet = NewError("需要内网环境", 18) 44 | ErrConfigPath = NewError("配置路径错误", 50) 45 | 46 | ErrFileRead = NewError("文件读取错误", 100) 47 | ErrDBDataType = NewError("数据库数据类型错误", 101) 48 | ErrNetTimeout = NewError("网络超时", 200) 49 | ErrNetUnreachable = NewError("网络不可达", 201) 50 | 51 | ErrClientReserve = NewError("客户端保留,服务器任何情况不会下发这个错误", 254) 52 | ErrErrIdNotFound = NewError("错误没有对应的错误码", 255) 53 | ) 54 | 55 | var MinUserError = 256 56 | 57 | func GetError(id uint16) *Error { 58 | if e, ok := idErrMap.Load(id); ok { 59 | return e.(*Error) 60 | } 61 | return ErrErrIdNotFound 62 | } 63 | 64 | func GetErrId(err error) uint16 { 65 | if id, ok := errIdMap.Load(err); ok { 66 | return id.(uint16) 67 | } 68 | id, _ := errIdMap.Load(ErrErrIdNotFound) 69 | return id.(uint16) 70 | } 71 | 72 | type ErrJsonStr struct { 73 | Error int `json:"error"` 74 | ErrorStr string `json:"errstr"` 75 | } 76 | 77 | func GetErrJsonStr(err error) string { 78 | return string(GetErrJsonData(err)) 79 | } 80 | func GetErrJsonData(err error) []byte { 81 | data, _ := JsonPack(&ErrJsonStr{Error: int(GetErrId(err)), ErrorStr: err.Error()}) 82 | return data 83 | } 84 | -------------------------------------------------------------------------------- /array_map.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | type ArrayMap struct { 4 | cap int32 5 | rawCap int32 6 | genArray []interface{} 7 | delArray []int32 8 | generArray []int32 9 | genIndex int32 10 | delIndex int32 11 | } 12 | 13 | func (r *ArrayMap) Clone() *ArrayMap { 14 | return &ArrayMap{ 15 | cap: r.cap, 16 | rawCap: r.rawCap, 17 | genArray: append([]interface{}{}, r.genArray...), 18 | delArray: append([]int32{}, r.delArray...), 19 | generArray: append([]int32{}, r.generArray...), 20 | genIndex: r.genIndex, 21 | delIndex: r.delIndex, 22 | } 23 | } 24 | 25 | func NewArrayMap(cap int32, fixedArray bool) *ArrayMap { 26 | m := &ArrayMap{ 27 | cap: cap, 28 | rawCap: cap, 29 | genArray: make([]interface{}, cap), 30 | delArray: make([]int32, cap), 31 | generArray: make([]int32, cap), 32 | genIndex: -1, 33 | delIndex: -1, 34 | } 35 | if fixedArray { 36 | m.genIndex = cap - 1 37 | } 38 | return m 39 | } 40 | 41 | func (r *ArrayMap) Add(value interface{}) int32 { 42 | var index int32 = -1 43 | if r.delIndex >= 0 { 44 | index = r.delArray[r.delIndex] 45 | r.delIndex-- 46 | } 47 | if index == -1 { 48 | index = r.genIndex + 1 49 | r.genIndex++ 50 | if index >= r.cap { 51 | newArray := make([]interface{}, r.rawCap) 52 | r.genArray = append(r.genArray, newArray...) 53 | newDelArray := make([]int32, r.rawCap) 54 | r.delArray = append(r.delArray, newDelArray...) 55 | newDelArray = make([]int32, r.rawCap) 56 | r.generArray = append(r.generArray, newDelArray...) 57 | r.cap += r.rawCap 58 | } 59 | } 60 | r.genArray[index] = value 61 | return index + (r.generArray[index] << 16) 62 | } 63 | 64 | func (r *ArrayMap) Set(key int32, value interface{}) { 65 | index := key & 0x0000FFFF 66 | r.genArray[index] = value 67 | } 68 | 69 | func (r *ArrayMap) Del(key int32) { 70 | index := key & 0x0000FFFF 71 | r.delArray[r.delIndex+1] = index 72 | r.genArray[index] = nil 73 | r.generArray[index]++ 74 | r.delIndex++ 75 | } 76 | func (r *ArrayMap) RawLen() int32 { 77 | return r.genIndex + 1 78 | } 79 | func (r *ArrayMap) RawGet(key int32) interface{} { 80 | if key >= r.cap { 81 | return nil 82 | } 83 | return r.genArray[key] 84 | } 85 | func (r *ArrayMap) Get(key int32) interface{} { 86 | index := key & 0x0000FFFF 87 | gener := key >> 16 88 | if index >= r.cap { 89 | return nil 90 | } 91 | if gener != r.generArray[index] { 92 | return nil 93 | } 94 | 95 | return r.genArray[index] 96 | } 97 | -------------------------------------------------------------------------------- /model_redis.go: -------------------------------------------------------------------------------- 1 | // 模型来自pb 2 | // 特别注意,lua只至此double,int64的数据如果进行cmsgpack打包解包可能出现精度问题导致bug 3 | package antnet 4 | 5 | import ( 6 | "github.com/golang/protobuf/proto" 7 | "github.com/vmihailenco/msgpack" 8 | ) 9 | 10 | type RedisModel struct{} 11 | 12 | func (r *RedisModel) DBData(v proto.Message) []byte { 13 | return DBData(v) 14 | } 15 | 16 | func (r *RedisModel) DBStr(v proto.Message) string { 17 | return DBStr(v) 18 | } 19 | 20 | func (r *RedisModel) PbData(v proto.Message) []byte { 21 | return PbData(v) 22 | } 23 | 24 | func (r *RedisModel) PbStr(v proto.Message) string { 25 | return PbStr(v) 26 | } 27 | 28 | func (r *RedisModel) ParseDBData(data []byte, v proto.Message) bool { 29 | return ParseDBData(data, v) 30 | } 31 | 32 | func (r *RedisModel) ParseDBStr(str string, v proto.Message) bool { 33 | return ParseDBStr(str, v) 34 | } 35 | 36 | func (r *RedisModel) ParsePbData(data []byte, v proto.Message) bool { 37 | return ParsePbData(data, v) 38 | } 39 | 40 | func (r *RedisModel) ParsePbStr(str string, v proto.Message) bool { 41 | return ParsePbStr(str, v) 42 | } 43 | 44 | func DBData(v proto.Message) []byte { 45 | data, err := msgpack.Marshal(v) 46 | if err != nil { 47 | LogError(err) 48 | } 49 | return data 50 | } 51 | 52 | func DBStr(v proto.Message) string { 53 | data, err := msgpack.Marshal(v) 54 | if err != nil { 55 | LogError(err) 56 | } 57 | return string(data) 58 | } 59 | 60 | func PbData(v proto.Message) []byte { 61 | data, err := proto.Marshal(v) 62 | if err != nil { 63 | LogError(err) 64 | } 65 | return data 66 | } 67 | 68 | func PbStr(v proto.Message) string { 69 | data, err := proto.Marshal(v) 70 | if err != nil { 71 | LogError(err) 72 | } 73 | return string(data) 74 | } 75 | 76 | func ParseDBData(data []byte, v proto.Message) bool { 77 | if err := msgpack.Unmarshal(data, v); err != nil { 78 | return ParsePbData(data, v) 79 | } 80 | return true 81 | } 82 | 83 | func ParseDBStr(str string, v proto.Message) bool { 84 | if err := msgpack.Unmarshal([]byte(str), v); err != nil { 85 | return ParsePbStr(str, v) 86 | } 87 | return true 88 | } 89 | 90 | func ParsePbData(data []byte, v proto.Message) bool { 91 | if err := proto.Unmarshal(data, v); err != nil { 92 | LogError(err) 93 | return false 94 | } 95 | return true 96 | } 97 | 98 | func ParsePbStr(str string, v proto.Message) bool { 99 | if err := proto.Unmarshal([]byte(str), v); err != nil { 100 | LogError(err) 101 | return false 102 | } 103 | return true 104 | } 105 | -------------------------------------------------------------------------------- /func_strings.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func SplitStr(s string, sep string) []string { 8 | return strings.Split(s, sep) 9 | } 10 | 11 | func StrSplit(s string, sep string) []string { 12 | return strings.Split(s, sep) 13 | } 14 | 15 | func SplitStrN(s string, sep string, n int) []string { 16 | return strings.SplitN(s, sep, n) 17 | } 18 | 19 | func StrSplitN(s string, sep string, n int) []string { 20 | return strings.SplitN(s, sep, n) 21 | } 22 | 23 | func StrFind(s string, f string) int { 24 | return strings.Index(s, f) 25 | } 26 | 27 | func FindStr(s string, f string) int { 28 | return strings.Index(s, f) 29 | } 30 | 31 | func ReplaceStr(s, old, new string) string { 32 | return strings.Replace(s, old, new, -1) 33 | } 34 | 35 | func StrReplace(s, old, new string) string { 36 | return strings.Replace(s, old, new, -1) 37 | } 38 | 39 | func ReplaceMultStr(s string, oldnew ...string) string { 40 | r := strings.NewReplacer(oldnew...) 41 | return r.Replace(s) 42 | } 43 | 44 | func StrReplaceMult(s string, oldnew ...string) string { 45 | r := strings.NewReplacer(oldnew...) 46 | return r.Replace(s) 47 | } 48 | 49 | func TrimStrSpace(s string) string { 50 | return strings.TrimSpace(s) 51 | } 52 | 53 | func StrTrimSpace(s string) string { 54 | return strings.TrimSpace(s) 55 | } 56 | 57 | func TrimStr(s string, cutset []string) string { 58 | for _, v := range cutset{ 59 | s = strings.Trim(s, v) 60 | } 61 | return s 62 | } 63 | 64 | func StrTrim(s string, cutset []string) string { 65 | return TrimStr(s, cutset) 66 | } 67 | 68 | func StrContains(s, substr string) bool { 69 | return strings.Contains(s, substr) 70 | } 71 | 72 | func ContainsStr(s, substr string) bool { 73 | return strings.Contains(s, substr) 74 | } 75 | 76 | func JoinStr(a []string, sep string) string { 77 | return strings.Join(a, sep) 78 | } 79 | 80 | func StrJoin(a []string, sep string) string { 81 | return strings.Join(a, sep) 82 | } 83 | 84 | func StrToLower(s string) string { 85 | return strings.ToLower(s) 86 | } 87 | 88 | func ToLowerStr(s string) string { 89 | return strings.ToLower(s) 90 | } 91 | 92 | func StrToUpper(s string) string { 93 | return strings.ToUpper(s) 94 | } 95 | 96 | func ToUpperStr(s string) string { 97 | return strings.ToUpper(s) 98 | } 99 | 100 | func StrTrimRight(s, cutset string) string { 101 | return strings.TrimRight(s, cutset) 102 | } 103 | 104 | func TrimRightStr(s, cutset string) string { 105 | return strings.TrimRight(s, cutset) 106 | } 107 | -------------------------------------------------------------------------------- /init.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "os" 5 | "runtime" 6 | "sync" 7 | "sync/atomic" 8 | "time" 9 | ) 10 | 11 | type Statis struct { 12 | GoCount int 13 | MsgqueCount int 14 | StartTime time.Time 15 | LastPanic int 16 | PanicCount int32 17 | PoolGoCount int32 18 | } 19 | 20 | var statis = &Statis{} 21 | 22 | type WaitGroup struct { 23 | count int64 24 | } 25 | 26 | func (r *WaitGroup) Add(delta int) { 27 | atomic.AddInt64(&r.count, int64(delta)) 28 | } 29 | 30 | func (r *WaitGroup) Done() { 31 | atomic.AddInt64(&r.count, -1) 32 | } 33 | 34 | func (r *WaitGroup) Wait() { 35 | for atomic.LoadInt64(&r.count) > 0 { 36 | Sleep(1) 37 | } 38 | } 39 | 40 | func (r *WaitGroup) TryWait() bool { 41 | return atomic.LoadInt64(&r.count) == 0 42 | } 43 | 44 | var waitAll = &WaitGroup{} //等待所有goroutine 45 | var waitAllForLog sync.WaitGroup 46 | var waitAllForRedis sync.WaitGroup 47 | 48 | var stopForLog int32 // 49 | var stop int32 //停止标志 50 | 51 | var gocount int32 //goroutine数量 52 | var goid uint32 53 | var DefLog *Log //日志 54 | 55 | var msgqueId uint32 //消息队列id 56 | var msgqueMapSync sync.Mutex 57 | var msgqueMap = map[uint32]IMsgQue{} 58 | 59 | type gMsg struct { 60 | c chan struct{} 61 | msg *Message 62 | fun func(msgque IMsgQue) bool 63 | } 64 | 65 | var gmsgId uint16 66 | var gmsgMapSync sync.Mutex 67 | var gmsgArray = [65536]*gMsg{} 68 | 69 | var atexitId uint32 70 | var atexitMapSync sync.Mutex 71 | var atexitMap = map[uint32]func(){} 72 | 73 | var stopChanForGo = make(chan struct{}) 74 | var stopChanForLog = make(chan struct{}) 75 | var stopChanForSys = make(chan os.Signal, 1) 76 | 77 | var poolChan = make(chan func()) 78 | var poolGoCount int32 79 | 80 | var StartTick int64 81 | var NowTick int64 82 | var Timestamp int64 // 当前秒数 83 | var TimeString string // 当前时间 格式:2020-7-9 14:59:15 84 | var randIndex uint32 = 0 85 | var Config = struct { 86 | AutoCompressLen uint32 87 | UdpServerGoCnt int 88 | PoolSize int32 89 | SSLCrtPath string 90 | SSLKeyPath string 91 | EnableWss bool 92 | ReadDataBuffer int 93 | StopTimeout int 94 | }{UdpServerGoCnt: 64, PoolSize: 50000, ReadDataBuffer: 1 << 12, StopTimeout: 3000} 95 | 96 | var stopCheckIndex uint64 97 | var stopCheckMap = struct { 98 | sync.Mutex 99 | M map[uint64]string 100 | }{M: map[uint64]string{}} 101 | 102 | func init() { 103 | gmsgArray[gmsgId] = &gMsg{c: make(chan struct{})} 104 | runtime.GOMAXPROCS(runtime.NumCPU()) 105 | DefLog = NewLog(10000, &ConsoleLogger{true}) 106 | DefLog.SetLevel(LogLevelInfo) 107 | timerTick() 108 | } 109 | -------------------------------------------------------------------------------- /container.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "container/heap" 5 | ) 6 | 7 | type item struct { 8 | value int // The value of the item; arbitrary. 9 | priority int // The priority of the item in the queue. 10 | index int // The index of the item in the heap. 11 | } 12 | 13 | type priorityQueue struct { 14 | im map[int]int 15 | m map[int]*item 16 | cf func(l, r *item) bool 17 | } 18 | 19 | func minHeapComp(l, r *item) bool { return l.priority < r.priority } 20 | func maxHeapComp(l, r *item) bool { return l.priority > r.priority } 21 | 22 | func (r *priorityQueue) Len() int { return len(r.im) } 23 | func (r *priorityQueue) Less(i, j int) bool { return r.cf(r.m[r.im[i]], r.m[r.im[j]]) } 24 | func (r *priorityQueue) Swap(i, j int) { 25 | r.im[i], r.im[j] = r.im[j], r.im[i] 26 | r.m[r.im[i]].index = i 27 | r.m[r.im[j]].index = j 28 | } 29 | 30 | func (r *priorityQueue) Push(x interface{}) { 31 | it := x.(*item) 32 | if _, ok := r.m[it.value]; !ok { 33 | n := len(r.im) 34 | it.index = n 35 | r.im[n] = it.value 36 | r.m[it.value] = it 37 | } else { 38 | LogWarn("heap can't insert repeated value:%v", it.value) 39 | } 40 | } 41 | 42 | func (r *priorityQueue) Pop() interface{} { 43 | n := len(r.im) 44 | it := r.m[r.im[n-1]] 45 | delete(r.im, n-1) 46 | delete(r.m, it.value) 47 | return it 48 | } 49 | 50 | type Heap struct { 51 | p *priorityQueue 52 | } 53 | 54 | func (r *Heap) Push(priority, value int) { 55 | heap.Push(r.p, &item{priority: priority, value: value}) 56 | } 57 | 58 | func (r *Heap) Pop() int { 59 | return heap.Pop(r.p).(*item).value 60 | } 61 | 62 | func (r *Heap) Update(value, priority int) { 63 | if it, ok := r.p.m[value]; ok { 64 | it.priority = priority 65 | heap.Fix(r.p, it.index) 66 | } 67 | } 68 | 69 | func (r *Heap) Top() int { 70 | _, v := r.GetMin() 71 | return v 72 | } 73 | 74 | func (r *Heap) GetMin() (priority int, value int) { 75 | it := heap.Pop(r.p).(*item) 76 | heap.Push(r.p, it) 77 | return it.priority, it.value 78 | } 79 | 80 | func (r *Heap) GetMax() (priority int, value int) { 81 | return r.GetMin() 82 | } 83 | 84 | func (r *Heap) GetPriority(value int) (priority int, find bool) { 85 | it, ok := r.p.m[value] 86 | return it.priority, ok 87 | } 88 | 89 | func (r *Heap) Len() int { 90 | return len(r.p.m) 91 | } 92 | 93 | func NewMinHeap() *Heap { 94 | h := &Heap{p: &priorityQueue{m: map[int]*item{}, im: map[int]int{}, cf: minHeapComp}} 95 | heap.Init(h.p) 96 | return h 97 | } 98 | 99 | func NewMaxHeap() *Heap { 100 | h := &Heap{p: &priorityQueue{m: map[int]*item{}, im: map[int]int{}, cf: maxHeapComp}} 101 | heap.Init(h.p) 102 | return h 103 | } 104 | -------------------------------------------------------------------------------- /func_compress.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "archive/zip" 5 | "bytes" 6 | "compress/gzip" 7 | "compress/zlib" 8 | "io" 9 | "io/ioutil" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | ) 14 | 15 | func ZlibCompress(data []byte) []byte { 16 | var in bytes.Buffer 17 | w := zlib.NewWriter(&in) 18 | w.Write(data) 19 | w.Close() 20 | return in.Bytes() 21 | } 22 | 23 | func ZlibUnCompress(data []byte) ([]byte, error) { 24 | b := bytes.NewReader(data) 25 | r, _ := zlib.NewReader(b) 26 | defer r.Close() 27 | undatas, err := ioutil.ReadAll(r) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return undatas, nil 32 | } 33 | 34 | func GZipCompress(data []byte) []byte { 35 | var in bytes.Buffer 36 | w := gzip.NewWriter(&in) 37 | w.Write(data) 38 | w.Close() 39 | return in.Bytes() 40 | } 41 | 42 | func GZipUnCompress(data []byte) ([]byte, error) { 43 | b := bytes.NewReader(data) 44 | r, _ := gzip.NewReader(b) 45 | defer r.Close() 46 | undatas, err := ioutil.ReadAll(r) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return undatas, nil 51 | } 52 | 53 | func Zip(srcFile string, destZip string) error { 54 | zipfile, err := os.Create(destZip) 55 | if err != nil { 56 | return err 57 | } 58 | defer zipfile.Close() 59 | 60 | archive := zip.NewWriter(zipfile) 61 | defer archive.Close() 62 | 63 | filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error { 64 | if err != nil { 65 | return err 66 | } 67 | 68 | header, err := zip.FileInfoHeader(info) 69 | if err != nil { 70 | return err 71 | } 72 | 73 | 74 | header.Name = strings.TrimPrefix(path, filepath.Dir(srcFile) + "/") 75 | // header.Name = path 76 | if info.IsDir() { 77 | header.Name += "/" 78 | } else { 79 | header.Method = zip.Deflate 80 | } 81 | 82 | writer, err := archive.CreateHeader(header) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | if ! info.IsDir() { 88 | file, err := os.Open(path) 89 | if err != nil { 90 | return err 91 | } 92 | defer file.Close() 93 | _, err = io.Copy(writer, file) 94 | } 95 | return err 96 | }) 97 | 98 | return err 99 | } 100 | 101 | func Unzip(zipFile string, destDir string) error { 102 | zipReader, err := zip.OpenReader(zipFile) 103 | if err != nil { 104 | return err 105 | } 106 | defer zipReader.Close() 107 | 108 | for _, f := range zipReader.File { 109 | fpath := filepath.Join(destDir, f.Name) 110 | if f.FileInfo().IsDir() { 111 | os.MkdirAll(fpath, os.ModePerm) 112 | } else { 113 | if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { 114 | return err 115 | } 116 | 117 | inFile, err := f.Open() 118 | if err != nil { 119 | return err 120 | } 121 | defer inFile.Close() 122 | 123 | outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) 124 | if err != nil { 125 | return err 126 | } 127 | defer outFile.Close() 128 | 129 | _, err = io.Copy(outFile, inFile) 130 | if err != nil { 131 | return err 132 | } 133 | } 134 | } 135 | return nil 136 | } -------------------------------------------------------------------------------- /parser_cmd.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "reflect" 5 | "strings" 6 | ) 7 | 8 | type CmdMatchType int 9 | 10 | const ( 11 | CmdMatchTypeK CmdMatchType = iota 12 | CmdMatchTypeKV 13 | ) 14 | 15 | type cmdParseNode struct { 16 | match CmdMatchType 17 | kind reflect.Kind 18 | index int 19 | name string 20 | c2sFunc ParseFunc 21 | s2cFunc ParseFunc 22 | next map[string]*cmdParseNode 23 | prev *cmdParseNode 24 | } 25 | type CmdParser struct { 26 | *Parser 27 | node *cmdParseNode 28 | values []interface{} 29 | match CmdMatchType 30 | } 31 | 32 | func (r *CmdParser) ParseC2S(msg *Message) (IMsgParser, error) { 33 | p, ok := r.parserString(string(msg.Data)) 34 | if ok { 35 | return p, nil 36 | } 37 | 38 | return nil, ErrCmdUnPack 39 | } 40 | 41 | func (r *CmdParser) PackMsg(v interface{}) []byte { 42 | data, _ := JsonPack(v) 43 | return data 44 | } 45 | 46 | func (r *CmdParser) GetRemindMsg(err error, t MsgType) *Message { 47 | if t == MsgTypeMsg { 48 | return nil 49 | } else { 50 | return nil 51 | } 52 | } 53 | 54 | func (r *CmdParser) parserString(s string) (IMsgParser, bool) { 55 | if r.node == nil { 56 | r.node = r.cmdRoot 57 | } 58 | s = strings.TrimSpace(s) 59 | cmds := strings.Split(s, " ") 60 | 61 | for _, v := range cmds { 62 | if r.match == CmdMatchTypeK { 63 | node, ok := r.node.next[v] 64 | if !ok { 65 | return nil, false 66 | } 67 | r.node = node 68 | if node.match == CmdMatchTypeK { 69 | continue 70 | } else { 71 | r.match = CmdMatchTypeKV 72 | continue 73 | } 74 | } 75 | i, err := ParseBaseKind(r.node.kind, v) 76 | if err != nil { 77 | return nil, false 78 | } 79 | 80 | r.match = CmdMatchTypeK 81 | r.values = append(r.values, i) 82 | } 83 | 84 | if r.node.next == nil { 85 | typ := reflect.ValueOf(r.node.c2sFunc()) 86 | ins := typ.Elem() 87 | i := len(r.values) 88 | s2cFunc := r.node.s2cFunc 89 | for r.node != nil { 90 | if r.node.match == CmdMatchTypeKV { 91 | ins.Field(r.node.index).Set(reflect.ValueOf(r.values[i-1])) 92 | i-- 93 | } else if r.node.kind == reflect.String && r.node != r.cmdRoot { 94 | ins.Field(r.node.index).SetString(r.node.name) 95 | } 96 | r.node = r.node.prev 97 | } 98 | return &MsgParser{c2s: typ.Interface(), parser: r, s2cFunc: s2cFunc}, true 99 | } 100 | return nil, false 101 | } 102 | 103 | func registerCmdParser(root *cmdParseNode, c2sFunc ParseFunc, s2cFunc ParseFunc) { 104 | msgType := reflect.TypeOf(c2sFunc()) 105 | if msgType == nil || msgType.Kind() != reflect.Ptr { 106 | LogFatal("message pointer required") 107 | return 108 | } 109 | typ := msgType.Elem() 110 | prevRoute := root 111 | 112 | for i := 0; i < typ.NumField(); i++ { 113 | field := typ.Field(i) 114 | name := strings.ToLower(field.Name) 115 | tag := field.Tag 116 | if prevRoute.next == nil { 117 | prevRoute.next = map[string]*cmdParseNode{} 118 | } 119 | c, ok := prevRoute.next[name] 120 | if !ok { 121 | c = &cmdParseNode{} 122 | c.prev = prevRoute 123 | 124 | if tag.Get("match") == "k" { 125 | c.match = CmdMatchTypeK 126 | } else { 127 | c.match = CmdMatchTypeKV 128 | } 129 | c.name = name 130 | c.kind = field.Type.Kind() 131 | c.index = i 132 | prevRoute.next[name] = c 133 | } 134 | prevRoute = c 135 | } 136 | 137 | prevRoute.s2cFunc = s2cFunc 138 | prevRoute.c2sFunc = c2sFunc 139 | } 140 | -------------------------------------------------------------------------------- /collision.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "math" 5 | "sort" 6 | ) 7 | 8 | type rigibody struct { 9 | value float64 10 | indexs []int 11 | Owner interface{} 12 | } 13 | 14 | type collisionMgr struct { 15 | cap int 16 | len int 17 | delLen int 18 | dirty bool 19 | rigibodys []*rigibody 20 | dels []*rigibody 21 | } 22 | 23 | func (r *collisionMgr) Len() int { 24 | if r.dirty { 25 | return r.len 26 | } 27 | return r.len - r.delLen 28 | } 29 | func (r *collisionMgr) Less(i, j int) bool { 30 | return r.rigibodys[i].value < r.rigibodys[j].value 31 | } 32 | func (r *collisionMgr) Swap(i, j int) { 33 | for x := 0; x < 2; x++ { 34 | if r.rigibodys[i].indexs[x] == i { 35 | r.rigibodys[i].indexs[x] = j 36 | break 37 | } 38 | } 39 | for x := 0; x < 2; x++ { 40 | if r.rigibodys[j].indexs[x] == j { 41 | r.rigibodys[j].indexs[x] = i 42 | break 43 | } 44 | } 45 | r.rigibodys[i], r.rigibodys[j] = r.rigibodys[j], r.rigibodys[i] 46 | } 47 | 48 | func (r *collisionMgr) Update(left, right float64, rb *rigibody){ 49 | r.rigibodys[rb.indexs[0]].value = left 50 | r.rigibodys[rb.indexs[1]].value = right 51 | } 52 | 53 | func (r *collisionMgr) Add(left, right float64, owner interface{}) *rigibody { 54 | var rb1, rb2 *rigibody 55 | if r.delLen > 0 { 56 | rb1 = r.dels[r.delLen-1] 57 | rb2 = r.dels[r.delLen-2] 58 | r.delLen -= 2 59 | 60 | rb1.Owner = owner 61 | rb2.Owner = owner 62 | rb1.value = left 63 | rb2.value = right 64 | } else { 65 | if r.len+2 > r.cap { 66 | rigibodys := make([]*rigibody, r.cap*2) 67 | dels := make([]*rigibody, r.cap*2) 68 | for x := 0; x < r.len; x++ { 69 | rigibodys[x] = r.rigibodys[x] 70 | dels[x] = r.dels[x] 71 | } 72 | r.rigibodys = rigibodys 73 | r.dels = dels 74 | r.cap *= 2 75 | } 76 | indexs := make([]int, 2, 2) 77 | rb1 = &rigibody{value: left, Owner: owner, indexs: indexs} 78 | rb2 = &rigibody{value: right, Owner: owner, indexs: indexs} 79 | indexs[0] = r.len 80 | r.rigibodys[r.len] = rb1 81 | indexs[1] = r.len + 1 82 | r.rigibodys[r.len+1] = rb2 83 | r.len += 2 84 | } 85 | r.dirty = true 86 | return rb1 87 | } 88 | 89 | func (r *collisionMgr) Del(rb *rigibody) { 90 | for x := 0; x < 2; x++ { 91 | rigibody := r.rigibodys[rb.indexs[x]] 92 | rigibody.value = math.MaxFloat64 93 | r.dels[r.delLen+x] = rigibody 94 | } 95 | r.delLen += 2 96 | r.dirty = true 97 | } 98 | 99 | func (r *collisionMgr) GetCollision(rb *rigibody) (re []*rigibody) { 100 | var min, max, xx int 101 | if rb.indexs[0] > rb.indexs[1] { 102 | min = rb.indexs[1] 103 | for xx = min; xx >= 0; xx-- { 104 | if r.rigibodys[xx].value == r.rigibodys[min].value { 105 | min = xx 106 | } else { 107 | break 108 | } 109 | } 110 | 111 | max = rb.indexs[0] 112 | for xx = max; xx < r.len; xx++ { 113 | if r.rigibodys[xx].value == r.rigibodys[max].value { 114 | max = xx 115 | } else { 116 | break 117 | } 118 | } 119 | } else { 120 | min = rb.indexs[0] 121 | for xx = min; xx >= 0; xx-- { 122 | if r.rigibodys[xx].value == r.rigibodys[min].value { 123 | min = xx 124 | } else { 125 | break 126 | } 127 | } 128 | 129 | max = rb.indexs[1] 130 | for xx = max; xx < r.len; xx++ { 131 | if r.rigibodys[xx].value == r.rigibodys[max].value { 132 | max = xx 133 | } else { 134 | break 135 | } 136 | } 137 | } 138 | for x := min; x <= max; x++ { 139 | if rb.Owner != r.rigibodys[x].Owner { 140 | re = append(re, r.rigibodys[x]) 141 | } 142 | } 143 | return 144 | } 145 | 146 | func (r *collisionMgr) Sort() { 147 | sort.Sort(r) 148 | r.dirty = false 149 | } 150 | 151 | func GetCollisionMgr(cap int) *collisionMgr { 152 | return &collisionMgr{ 153 | cap: cap, 154 | rigibodys: make([]*rigibody, cap), 155 | dels: make([]*rigibody, cap), 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /config_csv.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "encoding/csv" 5 | "os" 6 | "reflect" 7 | "strings" 8 | ) 9 | 10 | type GenConfigObj struct { 11 | GenObjFun func() interface{} 12 | ParseObjFun map[reflect.Kind]func(fieldv reflect.Value, data, path string) error 13 | } 14 | 15 | var csvParseMap = map[reflect.Kind]func(fieldv reflect.Value, data, path string) error{} 16 | 17 | func SetCSVParseFunc(kind reflect.Kind, fun func(fieldv reflect.Value, data, path string) error) { 18 | csvParseMap[kind] = fun 19 | } 20 | 21 | func GetCSVParseFunc(kind reflect.Kind) func(fieldv reflect.Value, data, path string) error { 22 | return csvParseMap[kind] 23 | } 24 | 25 | func setValue(fieldv reflect.Value, item, data, path string, line int, f *GenConfigObj) error { 26 | pm := csvParseMap 27 | if f.ParseObjFun != nil { 28 | pm = f.ParseObjFun 29 | } 30 | 31 | if fun, ok := pm[fieldv.Kind()]; ok { 32 | err := fun(fieldv, data, path) 33 | if err != nil { 34 | LogError("csv read error path:%v line:%v err:%v field:%v", path, line, err, item) 35 | } 36 | return err 37 | } else { 38 | v, err := ParseBaseKind(fieldv.Kind(), data) 39 | if err != nil { 40 | LogError("csv read error path:%v line:%v err:%v field:%v", path, line, err, item) 41 | return err 42 | } 43 | fieldv.Set(reflect.ValueOf(v)) 44 | } 45 | 46 | return nil 47 | } 48 | 49 | /* 50 | path 文件路径 51 | nindex key值行号,从1开始 52 | dataBegin 数据开始行号,从1开始 53 | f 对象产生器 json:"-" tag字段会被跳过 54 | */ 55 | func ReadConfigFromCSV(path string, nindex int, dataBegin int, f *GenConfigObj) (error, []interface{}) { 56 | csv_nimap := map[string]int{} 57 | nimap := map[string]int{} 58 | var dataObj []interface{} 59 | 60 | fi, err := os.Open(path) 61 | if err != nil { 62 | return err, nil 63 | } 64 | 65 | csvdata, err := csv.NewReader(fi).ReadAll() 66 | if err != nil { 67 | return err, nil 68 | } 69 | 70 | dataCount := len(csvdata) - dataBegin + 1 71 | dataObj = make([]interface{}, 0, dataCount) 72 | for index, name := range csvdata[nindex-1] { 73 | if name == "" { 74 | continue 75 | } 76 | bname := []byte(name) 77 | bname[0] = byte(int(bname[0]) & ^32) 78 | csv_nimap[string(bname)] = index 79 | } 80 | 81 | typ := reflect.ValueOf(f.GenObjFun()).Elem().Type() 82 | for i := 0; i < typ.NumField(); i++ { 83 | fieldt := typ.FieldByIndex([]int{i}) 84 | name := fieldt.Name 85 | if v, ok := csv_nimap[name]; ok { 86 | nimap[name] = v 87 | } else if fieldt.Tag.Get("json") != "-" { 88 | LogError("config index not found path:%s name:%s", path, name) 89 | return ErrCSVParse, nil 90 | } 91 | } 92 | 93 | for i := dataBegin - 1; i < len(csvdata); i++ { 94 | obj := f.GenObjFun() 95 | objv := reflect.ValueOf(obj) 96 | obje := objv.Elem() 97 | for k, v := range nimap { 98 | switch obje.FieldByName(k).Kind() { 99 | case reflect.Ptr: 100 | err = setValue(obje.FieldByName(k).Elem(), k, strings.TrimSpace(csvdata[i][v]), path, i+1, f) 101 | if err != nil { 102 | return err, nil 103 | } 104 | default: 105 | err = setValue(obje.FieldByName(k), k, strings.TrimSpace(csvdata[i][v]), path, i+1, f) 106 | if err != nil { 107 | return err, nil 108 | } 109 | } 110 | } 111 | dataObj = append(dataObj, obj) 112 | } 113 | 114 | return nil, dataObj 115 | } 116 | 117 | /*读取csv字段+值,竖着处理 118 | [in] path 文件路径 119 | [in] keyIndex 需要读取的字段列号 120 | [in] valueIndex 需要读取的字段数据列号 121 | [in] dataBegin 从哪一行开始输出 122 | */ 123 | func ReadConfigFromCSVLie(path string, keyIndex int, valueIndex int, dataBegin int, f *GenConfigObj) (error, interface{}) { 124 | fi, err := os.Open(path) 125 | if err != nil { 126 | return err, nil 127 | } 128 | 129 | csvdata, err := csv.NewReader(fi).ReadAll() 130 | if err != nil { 131 | return err, nil 132 | } 133 | 134 | obj := f.GenObjFun() 135 | robj := reflect.Indirect(reflect.ValueOf(obj)) 136 | for i := dataBegin - 1; i < len(csvdata); i++ { 137 | name := csvdata[i][keyIndex-1] 138 | bname := []byte(name) 139 | bname[0] = byte(int(bname[0]) & ^32) 140 | err = setValue(robj.FieldByName(string(bname)), string(bname), strings.TrimSpace(csvdata[i][valueIndex-1]), path, i+1, f) 141 | if err != nil { 142 | return err, nil 143 | } 144 | } 145 | 146 | return nil, obj 147 | } 148 | -------------------------------------------------------------------------------- /func_file.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "io" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | "path/filepath" 9 | "sync" 10 | "sync/atomic" 11 | ) 12 | 13 | func PathBase(p string) string { 14 | return path.Base(p) 15 | } 16 | 17 | func PathAbs(p string) string { 18 | f, err := filepath.Abs(p) 19 | if err != nil { 20 | LogError("get abs path failed path:%v err:%v", p, err) 21 | return "" 22 | } 23 | return f 24 | } 25 | 26 | func GetEXEDir() string { 27 | return PathDir(GetEXEPath()) 28 | } 29 | 30 | func GetEXEPath() string { 31 | return PathAbs(os.Args[0]) 32 | } 33 | 34 | func GetExeName() string { 35 | return PathBase(GetEXEPath()) 36 | } 37 | 38 | func GetExeDir() string { 39 | return PathDir(GetEXEPath()) 40 | } 41 | 42 | func GetExePath() string { 43 | return PathAbs(os.Args[0]) 44 | } 45 | 46 | func GetEXEName() string { 47 | return PathBase(GetEXEPath()) 48 | } 49 | 50 | func PathDir(p string) string { 51 | return path.Dir(p) 52 | } 53 | 54 | func PathExt(p string) string { 55 | return path.Ext(p) 56 | } 57 | 58 | func PathClean(p string) string { 59 | return path.Clean(p) 60 | } 61 | 62 | func PathExists(path string) bool { 63 | _, err := os.Stat(path) 64 | if err == nil { 65 | return true 66 | } 67 | if os.IsNotExist(err) { 68 | return false 69 | } 70 | return false 71 | } 72 | 73 | func NewDir(path string) error { 74 | return os.MkdirAll(path, 0777) 75 | } 76 | 77 | func ReadFile(path string) ([]byte, error) { 78 | data, err := ioutil.ReadFile(path) 79 | if err != nil { 80 | LogError("read file filed path:%v err:%v", path, err) 81 | return nil, ErrFileRead 82 | } 83 | return data, nil 84 | } 85 | 86 | func WriteFile(path string, data []byte) { 87 | dir := PathDir(path) 88 | if !PathExists(dir) { 89 | NewDir(dir) 90 | } 91 | ioutil.WriteFile(path, data, 0777) 92 | } 93 | 94 | func GetFiles(path string) []string { 95 | files := []string{} 96 | filepath.Walk(path, func(path string, f os.FileInfo, err error) error { 97 | if f == nil { 98 | return err 99 | } 100 | if f.IsDir() { 101 | return nil 102 | } 103 | files = append(files, path) 104 | return nil 105 | }) 106 | return files 107 | } 108 | 109 | func DelFile(path string) { 110 | os.Remove(path) 111 | } 112 | 113 | func DelDir(path string) { 114 | os.RemoveAll(path) 115 | } 116 | 117 | func CreateFile(path string) (*os.File, error) { 118 | dir := PathDir(path) 119 | if !PathExists(dir) { 120 | NewDir(dir) 121 | } 122 | return os.Create(path) 123 | } 124 | 125 | func CopyFile(dst io.Writer, src io.Reader) (written int64, err error) { 126 | return io.Copy(dst, src) 127 | } 128 | 129 | func walkDirTrue(dir string, level int, maxLevel int, wg *sync.WaitGroup, fun func(path string, info os.FileInfo)) { 130 | wg.Add(1) 131 | defer wg.Done() 132 | infos, err := ioutil.ReadDir(dir) 133 | if err != nil { 134 | LogError("walk dir failed dir:%v err:%v", dir, err) 135 | return 136 | } 137 | for _, info := range infos { 138 | if info.IsDir() { 139 | subDir := filepath.Join(dir, info.Name()) 140 | fun(subDir, info) 141 | if maxLevel > 0 && level+1 > maxLevel { 142 | continue 143 | } 144 | go walkDirTrue(subDir, level+1, maxLevel, wg, fun) 145 | } else { 146 | file := filepath.Join(dir, info.Name()) 147 | fun(file, info) 148 | } 149 | } 150 | } 151 | 152 | func WalkDir(dir string, maxLevel int, fun func(dir string, info os.FileInfo)) { 153 | if fun == nil { 154 | return 155 | } 156 | wg := &sync.WaitGroup{} 157 | walkDirTrue(dir, 0, maxLevel, wg, fun) 158 | wg.Wait() 159 | } 160 | 161 | func FileCount(dir string) int32 { 162 | var count int32 = 0 163 | WalkDir(dir, -1, func(dir string, info os.FileInfo) { 164 | if !info.IsDir() { 165 | atomic.AddInt32(&count, 1) 166 | } 167 | }) 168 | return count 169 | } 170 | 171 | func DirCount(dir string) int32 { 172 | var count int32 = 0 173 | WalkDir(dir, -1, func(dir string, info os.FileInfo) { 174 | if info.IsDir() { 175 | atomic.AddInt32(&count, 1) 176 | } 177 | }) 178 | return count 179 | } 180 | 181 | func DirSize(dir string) int64 { 182 | var size int64 = 0 183 | WalkDir(dir, -1, func(dir string, info os.FileInfo) { 184 | if !info.IsDir() { 185 | atomic.AddInt64(&size, info.Size()) 186 | } 187 | }) 188 | return size 189 | } 190 | -------------------------------------------------------------------------------- /parser.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | type IMsgParser interface { 8 | C2S() interface{} 9 | S2C() interface{} 10 | C2SData() []byte 11 | S2CData() []byte 12 | C2SString() string 13 | S2CString() string 14 | } 15 | 16 | type MsgParser struct { 17 | s2c interface{} 18 | c2s interface{} 19 | c2sFunc ParseFunc 20 | s2cFunc ParseFunc 21 | parser IParser 22 | } 23 | 24 | func (r *MsgParser) C2S() interface{} { 25 | if r.c2s == nil && r.c2sFunc != nil { 26 | r.c2s = r.c2sFunc() 27 | } 28 | return r.c2s 29 | } 30 | 31 | func (r *MsgParser) S2C() interface{} { 32 | if r.s2c == nil && r.s2cFunc != nil { 33 | r.s2c = r.s2cFunc() 34 | } 35 | return r.s2c 36 | } 37 | 38 | func (r *MsgParser) C2SData() []byte { 39 | return r.parser.PackMsg(r.C2S()) 40 | } 41 | 42 | func (r *MsgParser) S2CData() []byte { 43 | return r.parser.PackMsg(r.S2C()) 44 | } 45 | 46 | func (r *MsgParser) C2SString() string { 47 | return string(r.C2SData()) 48 | } 49 | 50 | func (r *MsgParser) S2CString() string { 51 | return string(r.S2CData()) 52 | } 53 | 54 | type ParserType int 55 | 56 | const ( 57 | ParserTypePB ParserType = iota //protobuf类型,用于和客户端交互 58 | ParserTypeCmd //cmd类型,类似telnet指令,用于直接和程序交互 59 | ParserTypeJson //json类型,可以用于客户端或者服务器之间交互 60 | ParserTypeMsgpack //msgpack类型,可以用于客户端或者服务器之间交互 61 | ParserTypeCustom //自定义类型 62 | ParserTypeRaw //不做任何解析 63 | ) 64 | 65 | type ParseErrType int 66 | 67 | const ( 68 | ParseErrTypeSendRemind ParseErrType = iota //消息解析失败发送提醒消息 69 | ParseErrTypeContinue //消息解析失败则跳过本条消息 70 | ParseErrTypeAlways //消息解析失败依然处理 71 | ParseErrTypeClose //消息解析失败则关闭连接 72 | ) 73 | 74 | type ParseFunc func() interface{} 75 | 76 | type IParser interface { 77 | GetType() ParserType 78 | GetErrType() ParseErrType 79 | ParseC2S(msg *Message) (IMsgParser, error) 80 | PackMsg(v interface{}) []byte 81 | GetRemindMsg(err error, t MsgType) *Message 82 | } 83 | 84 | type IParserFactory interface { 85 | Get() IParser 86 | } 87 | 88 | type Parser struct { 89 | Type ParserType 90 | ErrType ParseErrType 91 | 92 | msgMap map[int]MsgParser 93 | typMap map[reflect.Type]MsgParser 94 | cmdRoot *cmdParseNode 95 | parser IParser 96 | } 97 | 98 | func (r *Parser) Get() IParser { 99 | switch r.Type { 100 | case ParserTypePB: 101 | if r.parser == nil { 102 | r.parser = &PBParser{Parser: r} 103 | } 104 | case ParserTypeCmd: 105 | return &CmdParser{Parser: r} 106 | case ParserTypeJson: 107 | if r.parser == nil { 108 | r.parser = &JsonParser{Parser: r} 109 | } 110 | case ParserTypeMsgpack: 111 | if r.parser == nil { 112 | r.parser = &MsgpackParser{Parser: r} 113 | } 114 | case ParserTypeCustom: 115 | return nil 116 | case ParserTypeRaw: 117 | return nil 118 | } 119 | 120 | return r.parser 121 | } 122 | 123 | func (r *Parser) GetType() ParserType { 124 | return r.Type 125 | } 126 | 127 | func (r *Parser) GetErrType() ParseErrType { 128 | return r.ErrType 129 | } 130 | 131 | func (r *Parser) RegisterFunc(cmd, act uint8, c2sFunc ParseFunc, s2cFunc ParseFunc) { 132 | if r.msgMap == nil { 133 | r.msgMap = map[int]MsgParser{} 134 | } 135 | 136 | r.msgMap[CmdAct(cmd, act)] = MsgParser{c2sFunc: c2sFunc, s2cFunc: s2cFunc} 137 | } 138 | 139 | func (r *Parser) Register(cmd, act uint8, c2s interface{}, s2c interface{}) { 140 | var c2sFunc ParseFunc = nil 141 | var s2cFunc ParseFunc = nil 142 | 143 | if c2s != nil { 144 | c2sType := reflect.TypeOf(c2s).Elem() 145 | c2sFunc = func() interface{} { 146 | return reflect.New(c2sType).Interface() 147 | } 148 | } 149 | if s2c != nil { 150 | s2cType := reflect.TypeOf(s2c).Elem() 151 | s2cFunc = func() interface{} { 152 | return reflect.New(s2cType).Interface() 153 | } 154 | } 155 | r.RegisterFunc(cmd, act, c2sFunc, s2cFunc) 156 | } 157 | 158 | func (r *Parser) RegisterFuncById(id int, c2sFunc ParseFunc, s2cFunc ParseFunc) { 159 | if r.msgMap == nil { 160 | r.msgMap = map[int]MsgParser{} 161 | } 162 | 163 | r.msgMap[id] = MsgParser{c2sFunc: c2sFunc, s2cFunc: s2cFunc} 164 | } 165 | 166 | func (r *Parser) RegisterById(id int, c2s interface{}, s2c interface{}) { 167 | var c2sFunc ParseFunc = nil 168 | var s2cFunc ParseFunc = nil 169 | 170 | if c2s != nil { 171 | c2sType := reflect.TypeOf(c2s).Elem() 172 | c2sFunc = func() interface{} { 173 | return reflect.New(c2sType).Interface() 174 | } 175 | } 176 | if s2c != nil { 177 | s2cType := reflect.TypeOf(s2c).Elem() 178 | s2cFunc = func() interface{} { 179 | return reflect.New(s2cType).Interface() 180 | } 181 | } 182 | r.RegisterFuncById(id, c2sFunc, s2cFunc) 183 | } 184 | 185 | func (r *Parser) RegisterMsgFunc(c2sFunc ParseFunc, s2cFunc ParseFunc) { 186 | if r.Type == ParserTypeCmd { 187 | if r.cmdRoot == nil { 188 | r.cmdRoot = &cmdParseNode{} 189 | } 190 | registerCmdParser(r.cmdRoot, c2sFunc, s2cFunc) 191 | } else { 192 | if r.typMap == nil { 193 | r.typMap = map[reflect.Type]MsgParser{} 194 | } 195 | r.typMap[reflect.TypeOf(c2sFunc())] = MsgParser{c2sFunc: c2sFunc, s2cFunc: s2cFunc} 196 | } 197 | } 198 | 199 | func (r *Parser) RegisterMsg(c2s interface{}, s2c interface{}) { 200 | var c2sFunc ParseFunc = nil 201 | var s2cFunc ParseFunc = nil 202 | if c2s != nil { 203 | c2sType := reflect.TypeOf(c2s).Elem() 204 | c2sFunc = func() interface{} { 205 | return reflect.New(c2sType).Interface() 206 | } 207 | } 208 | if s2c != nil { 209 | s2cType := reflect.TypeOf(s2c).Elem() 210 | s2cFunc = func() interface{} { 211 | return reflect.New(s2cType).Interface() 212 | } 213 | } 214 | 215 | r.RegisterMsgFunc(c2sFunc, s2cFunc) 216 | } 217 | -------------------------------------------------------------------------------- /time.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func ParseTime(str string) (time.Time, error) { 8 | return time.Parse("2006-01-02 15:04:05", str) 9 | } 10 | 11 | func Date() string { 12 | return time.Now().Format("2006-01-02 15:04:05") 13 | } 14 | 15 | func UnixTime(sec, nsec int64) time.Time { 16 | return time.Unix(sec, nsec) 17 | } 18 | 19 | func UnixUs() int64 { 20 | return time.Now().UnixNano() / 1000 21 | } 22 | 23 | func UnixMs() int64 { 24 | return time.Now().UnixNano() / 1000000 25 | } 26 | 27 | func UnixNano() int64 { 28 | return time.Now().UnixNano() 29 | } 30 | 31 | func Now() time.Time { 32 | return time.Now() 33 | } 34 | 35 | func NewTimer(ms int) *time.Timer { 36 | return time.NewTimer(time.Millisecond * time.Duration(ms)) 37 | } 38 | 39 | func NewTicker(ms int) *time.Ticker { 40 | return time.NewTicker(time.Millisecond * time.Duration(ms)) 41 | } 42 | 43 | func After(ms int) <-chan time.Time { 44 | return time.After(time.Millisecond * time.Duration(ms)) 45 | } 46 | 47 | func Tick(ms int) <-chan time.Time { 48 | return time.Tick(time.Millisecond * time.Duration(ms)) 49 | } 50 | 51 | func Sleep(ms int) { 52 | time.Sleep(time.Millisecond * time.Duration(ms)) 53 | } 54 | 55 | func SetTimeout(inteval int, fn func(...interface{}) int, args ...interface{}) { 56 | if inteval < 0 { 57 | LogError("new timeout inteval:%v ms", inteval) 58 | return 59 | } 60 | LogInfo("new timeout inteval:%v ms", inteval) 61 | 62 | Go2(func(cstop chan struct{}) { 63 | tick := time.NewTimer(time.Millisecond * time.Duration(inteval)) 64 | for inteval > 0 { 65 | select { 66 | case <-cstop: 67 | inteval = 0 68 | case <-tick.C: 69 | inteval = fn(args...) 70 | if inteval > 0 { 71 | tick.Reset(time.Millisecond * time.Duration(inteval)) 72 | } 73 | } 74 | } 75 | tick.Stop() 76 | }) 77 | } 78 | 79 | func timerTick() { 80 | now := time.Now() 81 | StartTick = now.UnixNano() / 1000000 82 | NowTick = StartTick 83 | Timestamp = NowTick / 1000 84 | TimeString = now.Format("2006-01-02 15:04:05") 85 | lastTimestamp := Timestamp 86 | var ticker = time.NewTicker(time.Millisecond) 87 | Go(func() { 88 | for IsRuning() { 89 | select { 90 | case <-ticker.C: 91 | now := time.Now() 92 | NowTick = now.UnixNano() / 1000000 93 | Timestamp = NowTick / 1000 94 | if Timestamp != lastTimestamp { 95 | lastTimestamp = Timestamp 96 | TimeString = now.Format("2006-01-02 15:04:05") 97 | } 98 | } 99 | } 100 | ticker.Stop() 101 | }) 102 | } 103 | 104 | /** 105 | * @brief 获得timestamp距离下个小时的时间,单位s 106 | * 107 | * @return uint32_t 距离下个小时的时间,单位s 108 | */ 109 | func GetNextHourIntervalS() int { 110 | return int(3600 - (Timestamp % 3600)) 111 | } 112 | 113 | /** 114 | * @brief 获得timestamp距离下个小时的时间,单位ms 115 | * 116 | * @return uint32_t 距离下个小时的时间,单位ms 117 | */ 118 | func GetNextHourIntervalMS() int { 119 | return GetNextHourIntervalS() * 1000 120 | } 121 | 122 | /** 123 | * @brief 时间戳转换为小时,24小时制,0点用24表示 124 | * 125 | * @param timestamp 时间戳 126 | * @param timezone 时区 127 | * @return uint32_t 小时 范围 1-24 128 | */ 129 | func GetHour24(timestamp int64, timezone int) int { 130 | hour := int((timestamp%86400)/3600) + timezone 131 | if hour > 24 { 132 | return hour - 24 133 | } 134 | return hour 135 | } 136 | 137 | /** 138 | * @brief 时间戳转换为小时,24小时制,0点用0表示 139 | * 140 | * @param timestamp 时间戳 141 | * @param timezone 时区 142 | * @return uint32_t 小时 范围 0-23 143 | */ 144 | func GetHour23(timestamp int64, timezone int) int { 145 | hour := GetHour24(timestamp, timezone) 146 | if hour == 24 { 147 | return 0 //24点就是0点 148 | } 149 | return hour 150 | } 151 | 152 | func GetHour(timestamp int64, timezone int) int { 153 | return GetHour23(timestamp, timezone) 154 | } 155 | 156 | /** 157 | * @brief 判断两个时间戳是否是同一天 158 | * 159 | * @param now 需要比较的时间戳 160 | * @param old 需要比较的时间戳 161 | * @param timezone 时区 162 | * @return uint32_t 返回不同的天数 163 | */ 164 | func IsDiffDay(now, old int64, timezone int) int { 165 | now += int64(timezone * 3600) 166 | old += int64(timezone * 3600) 167 | return int((now / 86400) - (old / 86400)) 168 | } 169 | 170 | /** 171 | * @brief 判断时间戳是否处于两个小时之内 172 | * 173 | * @param now 需要比较的时间戳 174 | * @param hour_start 起始的小时 0 -23 175 | * @param hour_end 结束的小时 0 -23 176 | * @param timezone 时区 177 | * @return bool true表示处于两个小时之间 178 | */ 179 | func IsBetweenHour(now int64, hour_start, hour_end int, timezone int) bool { 180 | hour := GetHour23(now, timezone) 181 | return (hour >= hour_start) && (hour < hour_end) 182 | } 183 | 184 | /** 185 | * @brief 判断时间戳是否处于一个小时的两边,即一个时间错大于当前的hour,一个小于 186 | * 187 | * @param now 需要比较的时间戳 188 | * @param old 需要比较的时间戳 189 | * @param hour 小时,0-23 190 | * @param timezone 时区 191 | * @return bool true表示时间戳是否处于一个小时的两边 192 | */ 193 | func IsDiffHour(now, old int64, hour, timezone int) bool { 194 | diff := IsDiffDay(now, old, timezone) 195 | if diff == 1 { 196 | if GetHour23(old, timezone) > hour { 197 | return GetHour23(now, timezone) >= hour 198 | } else { 199 | return true 200 | } 201 | } else if diff >= 2 { 202 | return true 203 | } 204 | 205 | return (GetHour23(now, timezone) >= hour) && (GetHour23(old, timezone) < hour) 206 | } 207 | 208 | /** 209 | * @brief 判断时间戳是否处于跨周, 在周一跨天节点的两边 210 | * 211 | * @param now 需要比较的时间戳 212 | * @param old 需要比较的时间戳 213 | * @param hour 小时,0-23 214 | * @param timezone 时区 215 | * @return bool true表示时间戳是否处于跨周, 在周一跨天节点的两边 216 | */ 217 | func IsDiffWeek(now, old int64, hour, timezone int) bool { 218 | diffHour := IsDiffHour(now, old, hour, timezone) 219 | now += int64(timezone * 3600) 220 | old += int64(timezone * 3600) 221 | // 使用UTC才能在本地时间采用周一作为一周的开始 222 | _, nw := time.Unix(now, 0).UTC().ISOWeek() 223 | _, ow := time.Unix(old, 0).UTC().ISOWeek() 224 | return nw != ow && diffHour 225 | } 226 | 227 | /* 今天零点 228 | * timezone 时区 229 | * return 零点时间 230 | */ 231 | func ZeroTime(timezone int) int64 { 232 | timeStr := time.Now().Format("2006-01-02") 233 | t, _ := time.Parse("2006-01-02", timeStr) 234 | return t.Unix() - int64(timezone*3600) 235 | } 236 | 237 | /* 年月日 238 | * timestamp 时间 239 | * timezone 时区 240 | * return year,month,day 241 | */ 242 | func YearMonthDay(timestamp int64, timezone int) (int32, int32, int32) { 243 | timestamp += int64(timezone * 3600) 244 | year, month, day := time.Unix(timestamp, 0).UTC().Date() 245 | return int32(year), int32(month), int32(day) 246 | } 247 | -------------------------------------------------------------------------------- /func_net.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "io/ioutil" 7 | "mime/multipart" 8 | "net" 9 | "net/http" 10 | "net/smtp" 11 | "os" 12 | "strings" 13 | ) 14 | 15 | func Send(msg *Message, fun func(msgque IMsgQue) bool) { 16 | if msg == nil { 17 | return 18 | } 19 | c := make(chan struct{}) 20 | gmsgMapSync.Lock() 21 | gmsg := gmsgArray[gmsgId] 22 | gmsgArray[gmsgId+1] = &gMsg{c: c} 23 | gmsgId++ 24 | gmsgMapSync.Unlock() 25 | gmsg.msg = msg 26 | gmsg.fun = fun 27 | close(gmsg.c) 28 | } 29 | 30 | func SendGroup(group string, msg *Message) { 31 | Send(msg, func(msgque IMsgQue) bool { 32 | return msgque.IsInGroup(group) 33 | }) 34 | } 35 | 36 | func HttpGetWithBasicAuth(url, name, passwd string) (string, error, *http.Response) { 37 | client := &http.Client{} 38 | req, err := http.NewRequest("GET", url, nil) 39 | if err != nil { 40 | return "", ErrHttpRequest, nil 41 | } 42 | req.SetBasicAuth(name, passwd) 43 | resp, err := client.Do(req) 44 | if err != nil { 45 | return "", ErrHttpRequest, nil 46 | } 47 | defer resp.Body.Close() 48 | body, err := ioutil.ReadAll(resp.Body) 49 | if err != nil { 50 | return "", ErrHttpRequest, nil 51 | } 52 | return string(body), nil, resp 53 | } 54 | 55 | func HttpGet(url string) (string, error, *http.Response) { 56 | resp, err := http.Get(url) 57 | if err != nil { 58 | return "", ErrHttpRequest, nil 59 | } 60 | defer resp.Body.Close() 61 | body, err := ioutil.ReadAll(resp.Body) 62 | if err != nil { 63 | return "", ErrHttpRequest, resp 64 | } 65 | return string(body), nil, resp 66 | } 67 | 68 | func HttpPost(url, form string) (string, error, *http.Response) { 69 | resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(form)) 70 | if err != nil { 71 | return "", ErrHttpRequest, nil 72 | } 73 | defer resp.Body.Close() 74 | body, err := ioutil.ReadAll(resp.Body) 75 | if err != nil { 76 | return "", ErrHttpRequest, resp 77 | } 78 | return string(body), nil, resp 79 | } 80 | 81 | func HttpPostJson(url string, body string) (string, error, *http.Response) { 82 | res, err := http.Post(url, "application/json", strings.NewReader(body)) 83 | if err != nil { 84 | return "", ErrHttpRequest, nil 85 | } 86 | defer res.Body.Close() 87 | resBody, err := ioutil.ReadAll(res.Body) 88 | if err != nil { 89 | return "", ErrHttpRequest, res 90 | } 91 | return string(resBody), nil, res 92 | } 93 | 94 | func HttpUpload(url, field, file string) (*http.Response, error) { 95 | buf := new(bytes.Buffer) 96 | writer := multipart.NewWriter(buf) 97 | formFile, err := writer.CreateFormFile(field, file) 98 | if err != nil { 99 | LogError("create form file failed:%s\n", err) 100 | return nil, err 101 | } 102 | 103 | srcFile, err := os.Open(file) 104 | if err != nil { 105 | LogError("%open source file failed:%s\n", err) 106 | return nil, err 107 | } 108 | defer srcFile.Close() 109 | _, err = io.Copy(formFile, srcFile) 110 | if err != nil { 111 | LogError("write to form file falied:%s\n", err) 112 | return nil, err 113 | } 114 | 115 | contentType := writer.FormDataContentType() 116 | writer.Close() 117 | resp, err := http.Post(url, contentType, buf) 118 | if err != nil { 119 | LogError("post failed:%s\n", err) 120 | } 121 | resp.Body.Close() 122 | return resp, err 123 | } 124 | 125 | func SendMail(user, password, host, to, subject, body, mailtype string) error { 126 | hp := strings.Split(host, ":") 127 | auth := smtp.PlainAuth("", user, password, hp[0]) 128 | var content_type string 129 | if mailtype == "html" { 130 | content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8" 131 | } else { 132 | content_type = "Content-Type: text/plain" + "; charset=UTF-8" 133 | } 134 | 135 | msg := []byte("To: " + to + "\r\nFrom: " + user + ">\r\nSubject: " + "\r\n" + content_type + "\r\n\r\n" + body) 136 | send_to := strings.Split(to, ";") 137 | err := smtp.SendMail(host, auth, user, send_to, msg) 138 | return err 139 | } 140 | 141 | var allIp []string 142 | 143 | func GetSelfIp(ifnames ...string) []string { 144 | if allIp != nil { 145 | return allIp 146 | } 147 | inters, _ := net.Interfaces() 148 | if len(ifnames) == 0 { 149 | ifnames = []string{"eth", "lo", "eno", "无线网络连接", "以太网", "WLAN", "本地连接"} 150 | } 151 | 152 | filterFunc := func(name string) bool { 153 | for _, v := range ifnames { 154 | if strings.Index(name, v) != -1 { 155 | return true 156 | } 157 | } 158 | return false 159 | } 160 | 161 | for _, inter := range inters { 162 | if !filterFunc(inter.Name) { 163 | continue 164 | } 165 | addrs, _ := inter.Addrs() 166 | for _, a := range addrs { 167 | if ipnet, ok := a.(*net.IPNet); ok { 168 | if ipnet.IP.To4() != nil { 169 | allIp = append(allIp, ipnet.IP.String()) 170 | } 171 | } 172 | } 173 | } 174 | return allIp 175 | } 176 | 177 | func IsIpAddress(ip string) bool { 178 | address := net.ParseIP(ip) 179 | if address != nil { 180 | return true 181 | } 182 | return false 183 | } 184 | 185 | func IsIntraIp(ip string) bool { 186 | if ip == "127.0.0.1" { 187 | return true 188 | } 189 | ips := strings.Split(ip, ".") 190 | ipA := ips[0] 191 | if ipA == "10" { 192 | return true 193 | } 194 | ipB := ips[1] 195 | 196 | if ipA == "192" { 197 | if ipB == "168" { 198 | return true 199 | } 200 | } 201 | 202 | if ipA == "172" { 203 | ipb := Atoi(ipB) 204 | if ipb >= 16 && ipb <= 31 { 205 | return true 206 | } 207 | } 208 | 209 | return false 210 | } 211 | 212 | func GetSelfIntraIp(ifnames ...string) (ips []string) { 213 | all := GetSelfIp(ifnames...) 214 | for _, v := range all { 215 | if IsIntraIp(v) { 216 | ips = append(ips, v) 217 | } 218 | } 219 | 220 | return 221 | } 222 | 223 | func GetSelfExtraIp(ifnames ...string) (ips []string) { 224 | all := GetSelfIp(ifnames...) 225 | for _, v := range all { 226 | if IsIntraIp(v) { 227 | continue 228 | } 229 | ips = append(ips, v) 230 | } 231 | 232 | return 233 | } 234 | 235 | func IPCanUse(ip string) bool { 236 | var err error 237 | for port := 1024; port < 65535; port++ { 238 | addr := Sprintf("%v:%v", ip, port) 239 | listen, err := net.Listen("tcp", addr) 240 | if err == nil { 241 | listen.Close() 242 | break 243 | } else if StrFind(err.Error(), "address is not valid") != -1 { 244 | return false 245 | } 246 | } 247 | return err == nil 248 | } 249 | -------------------------------------------------------------------------------- /msgque_msg.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | const ( 9 | MsgHeadSize = 12 10 | ) 11 | 12 | const ( 13 | FlagEncrypt = 1 << 0 //数据是经过加密的 14 | FlagCompress = 1 << 1 //数据是经过压缩的 15 | FlagCanDiscard = 1 << 2 //消息是否可以丢弃,基于tcp网络的帧同步中,包可以主动丢弃 16 | FlagNeedAck = 1 << 3 //消息需要确认 17 | FlagAck = 1 << 4 //确认消息 18 | FlagReSend = 1 << 5 //重发消息 19 | FlagClient = 1 << 6 //消息来自客服端,用于判断index来之服务器还是其他玩家 20 | FlagUdpProxy = 1 << 7 //udp代理 21 | ) 22 | 23 | var MaxMsgDataSize uint32 = 1024 * 1024 24 | 25 | type MessageHead struct { 26 | Len uint32 //数据长度 27 | Error uint16 //错误码 28 | Cmd uint8 //命令 29 | Act uint8 //动作 30 | Index uint16 //序号 31 | Flags uint16 //标记 32 | 33 | forever bool 34 | data []byte 35 | } 36 | 37 | func (r *MessageHead) Bytes() []byte { 38 | if r.forever && r.data != nil { 39 | return r.data 40 | } 41 | r.data = make([]byte, MsgHeadSize) 42 | phead := (*MessageHead)(unsafe.Pointer(&r.data[0])) 43 | phead.Len = r.Len 44 | phead.Error = r.Error 45 | phead.Cmd = r.Cmd 46 | phead.Act = r.Act 47 | phead.Index = r.Index 48 | phead.Flags = r.Flags 49 | return r.data 50 | } 51 | 52 | func (r *MessageHead) FastBytes(data []byte) []byte { 53 | phead := (*MessageHead)(unsafe.Pointer(&data[0])) 54 | phead.Len = r.Len 55 | phead.Error = r.Error 56 | phead.Cmd = r.Cmd 57 | phead.Act = r.Act 58 | phead.Index = r.Index 59 | phead.Flags = r.Flags 60 | return data 61 | } 62 | 63 | func (r *MessageHead) BytesWithData(wdata []byte) []byte { 64 | if r.forever && r.data != nil { 65 | return r.data 66 | } 67 | r.Len = uint32(len(wdata)) 68 | r.data = make([]byte, MsgHeadSize+r.Len) 69 | phead := (*MessageHead)(unsafe.Pointer(&r.data[0])) 70 | phead.Len = r.Len 71 | phead.Error = r.Error 72 | phead.Cmd = r.Cmd 73 | phead.Act = r.Act 74 | phead.Index = r.Index 75 | phead.Flags = r.Flags 76 | if wdata != nil { 77 | copy(r.data[MsgHeadSize:], wdata) 78 | } 79 | return r.data 80 | } 81 | 82 | func (r *MessageHead) FromBytes(data []byte) error { 83 | if len(data) < MsgHeadSize { 84 | return ErrMsgLenTooShort 85 | } 86 | phead := (*MessageHead)(unsafe.Pointer(&data[0])) 87 | r.Len = phead.Len 88 | r.Error = phead.Error 89 | r.Cmd = phead.Cmd 90 | r.Act = phead.Act 91 | r.Index = phead.Index 92 | r.Flags = phead.Flags 93 | if r.Len > MaxMsgDataSize { 94 | return ErrMsgLenTooLong 95 | } 96 | return nil 97 | } 98 | 99 | func (r *MessageHead) CmdAct() int { 100 | return CmdAct(r.Cmd, r.Act) 101 | } 102 | 103 | func (r *MessageHead) Tag() int { 104 | return Tag(r.Cmd, r.Act, r.Index) 105 | } 106 | 107 | func (r *MessageHead) String() string { 108 | return fmt.Sprintf("Len:%v Error:%v Cmd:%v Act:%v Index:%v Flags:%v", r.Len, r.Error, r.Cmd, r.Act, r.Index, r.Flags) 109 | } 110 | 111 | func NewMessageHead(data []byte) *MessageHead { 112 | head := &MessageHead{} 113 | if err := head.FromBytes(data); err != nil { 114 | return nil 115 | } 116 | return head 117 | } 118 | 119 | func MessageHeadFromByte(data []byte) *MessageHead { 120 | if len(data) < MsgHeadSize { 121 | return nil 122 | } 123 | phead := new(*MessageHead) 124 | *phead = (*MessageHead)(unsafe.Pointer(&data[0])) 125 | if (*phead).Len > MaxMsgDataSize { 126 | return nil 127 | } 128 | return *phead 129 | } 130 | 131 | type Message struct { 132 | Head *MessageHead //消息头,可能为nil 133 | Data []byte //消息数据 134 | IMsgParser //解析器 135 | User interface{} //用户自定义数据 136 | } 137 | 138 | func (r *Message) CmdAct() int { 139 | if r.Head != nil { 140 | return CmdAct(r.Head.Cmd, r.Head.Act) 141 | } 142 | return 0 143 | } 144 | 145 | func (r *Message) Len() uint32 { 146 | if r.Head != nil { 147 | return r.Head.Len 148 | } 149 | return 0 150 | } 151 | 152 | func (r *Message) Error() uint16 { 153 | if r.Head != nil { 154 | return r.Head.Error 155 | } 156 | return 0 157 | } 158 | 159 | func (r *Message) Cmd() uint8 { 160 | if r.Head != nil { 161 | return r.Head.Cmd 162 | } 163 | return 0 164 | } 165 | 166 | func (r *Message) Act() uint8 { 167 | if r.Head != nil { 168 | return r.Head.Act 169 | } 170 | return 0 171 | } 172 | 173 | func (r *Message) Index() uint16 { 174 | if r.Head != nil { 175 | return r.Head.Index 176 | } 177 | return 0 178 | } 179 | 180 | func (r *Message) Flags() uint16 { 181 | if r.Head != nil { 182 | return r.Head.Flags 183 | } 184 | return 0 185 | } 186 | 187 | func (r *Message) Tag() int { 188 | if r.Head != nil { 189 | return Tag(r.Head.Cmd, r.Head.Act, r.Head.Index) 190 | } 191 | return 0 192 | } 193 | 194 | func (r *Message) Bytes() []byte { 195 | if r.Head != nil { 196 | if r.Data != nil { 197 | return r.Head.BytesWithData(r.Data) 198 | } 199 | return r.Head.Bytes() 200 | } 201 | return r.Data 202 | } 203 | 204 | func (r *Message) CopyTag(old *Message) *Message { 205 | if r.Head != nil && old.Head != nil { 206 | r.Head.Cmd = old.Head.Cmd 207 | r.Head.Act = old.Head.Act 208 | r.Head.Index = old.Head.Index 209 | } 210 | return r 211 | } 212 | 213 | func NewErrMsg(err error) *Message { 214 | errcode, ok := errIdMap.Load(err) 215 | if !ok { 216 | errcode, _ = errIdMap.Load(ErrErrIdNotFound) 217 | } 218 | return &Message{ 219 | Head: &MessageHead{ 220 | Error: errcode.(uint16), 221 | }, 222 | } 223 | } 224 | 225 | func NewStrMsg(str string) *Message { 226 | return &Message{ 227 | Data: []byte(str), 228 | } 229 | } 230 | 231 | func NewDataMsg(data []byte) *Message { 232 | return &Message{ 233 | Head: &MessageHead{ 234 | Len: uint32(len(data)), 235 | }, 236 | Data: data, 237 | } 238 | } 239 | 240 | func NewMsg(cmd, act uint8, index, err uint16, data []byte) *Message { 241 | return &Message{ 242 | Head: &MessageHead{ 243 | Len: uint32(len(data)), 244 | Error: err, 245 | Cmd: cmd, 246 | Act: act, 247 | Index: index, 248 | }, 249 | Data: data, 250 | } 251 | } 252 | 253 | func NewForverMsg(cmd, act uint8, index, err uint16, data []byte) *Message { 254 | msg := &Message{ 255 | Head: &MessageHead{ 256 | Len: uint32(len(data)), 257 | Error: err, 258 | Cmd: cmd, 259 | Act: act, 260 | Index: index, 261 | forever: true, 262 | }, 263 | Data: data, 264 | } 265 | msg.Head.data = msg.Bytes() 266 | return msg 267 | } 268 | 269 | func NewTagMsg(cmd, act uint8, index uint16) *Message { 270 | return &Message{ 271 | Head: &MessageHead{ 272 | Cmd: cmd, 273 | Act: act, 274 | Index: index, 275 | }, 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /msgque_udp.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "net" 5 | "sync" 6 | "sync/atomic" 7 | "time" 8 | ) 9 | 10 | type udpMsgQue struct { 11 | msgQue 12 | conn *net.UDPConn //连接 13 | cread chan []byte //写入通道 14 | addr *net.UDPAddr 15 | sync.Mutex 16 | } 17 | 18 | type udpMsgQueHelper struct { 19 | init int32 20 | null bool 21 | sync.Mutex 22 | *udpMsgQue 23 | } 24 | 25 | func (r *udpMsgQue) GetNetType() NetType { 26 | return NetTypeUdp 27 | } 28 | 29 | func (r *udpMsgQue) Stop() { 30 | if atomic.CompareAndSwapInt32(&r.stop, 0, 1) { 31 | Go(func() { 32 | if r.init { 33 | r.handler.OnDelMsgQue(r) 34 | } 35 | r.available = false 36 | if r.cread != nil { 37 | close(r.cread) 38 | } 39 | 40 | udpMapLock.Lock() 41 | delete(udpMap, r.addr.String()) 42 | udpMapLock.Unlock() 43 | r.baseStop() 44 | }) 45 | } 46 | } 47 | 48 | func (r *udpMsgQue) IsStop() bool { 49 | if r.stop == 0 { 50 | if IsStop() { 51 | r.Stop() 52 | } 53 | } 54 | return r.stop == 1 55 | } 56 | 57 | func (r *udpMsgQue) LocalAddr() string { 58 | if r.conn != nil { 59 | return r.conn.LocalAddr().String() 60 | } 61 | return "" 62 | } 63 | 64 | func (r *udpMsgQue) RemoteAddr() string { 65 | if r.realRemoteAddr != "" { 66 | return r.realRemoteAddr 67 | } 68 | if r.addr != nil { 69 | return r.addr.String() 70 | } 71 | return "" 72 | } 73 | 74 | func (r *udpMsgQue) read() { 75 | defer func() { 76 | if err := recover(); err != nil { 77 | LogError("msgque read panic id:%v err:%v", r.id, err.(error)) 78 | LogStack() 79 | } 80 | r.Stop() 81 | }() 82 | var data []byte 83 | for !r.IsStop() { 84 | select { 85 | case data = <-r.cread: 86 | } 87 | if data == nil { 88 | break 89 | } 90 | var msg *Message 91 | if r.msgTyp == MsgTypeCmd { 92 | msg = &Message{Data: data} 93 | } else { 94 | head := MessageHeadFromByte(data) 95 | if head == nil { 96 | break 97 | } 98 | if head.Len > 0 { 99 | msg = &Message{Head: head, Data: data[MsgHeadSize:]} 100 | } else { 101 | msg = &Message{Head: head} 102 | } 103 | } 104 | r.lastTick = Timestamp 105 | if !r.init { 106 | if !r.handler.OnNewMsgQue(r) { 107 | break 108 | } 109 | r.init = true 110 | } 111 | 112 | if !r.processMsg(r, msg) { 113 | break 114 | } 115 | } 116 | } 117 | 118 | func (r *udpMsgQue) write() { 119 | defer func() { 120 | if err := recover(); err != nil { 121 | LogError("msgque write panic id:%v err:%v", r.id, err.(error)) 122 | LogStack() 123 | } 124 | r.Stop() 125 | }() 126 | gm := r.getGMsg(false) 127 | tick := time.NewTimer(time.Second * time.Duration(r.timeout)) 128 | for !r.IsStop() { 129 | var m *Message = nil 130 | select { 131 | case <-stopChanForGo: 132 | case m = <-r.cwrite: 133 | case <-gm.c: 134 | if gm.fun == nil || gm.fun(r) { 135 | m = gm.msg 136 | } 137 | gm = r.getGMsg(true) 138 | case <-tick.C: 139 | if r.isTimeout(tick) { 140 | r.Stop() 141 | } 142 | } 143 | 144 | if m == nil { 145 | continue 146 | } 147 | 148 | if r.msgTyp == MsgTypeCmd { 149 | if m.Data != nil { 150 | r.conn.WriteToUDP(m.Data, r.addr) 151 | } 152 | } else { 153 | if m.Head != nil || m.Data != nil { 154 | r.conn.WriteToUDP(m.Bytes(), r.addr) 155 | } 156 | } 157 | 158 | r.lastTick = Timestamp 159 | } 160 | 161 | tick.Stop() 162 | } 163 | 164 | func (r *udpMsgQue) sendRead(data []byte, n int) (re bool) { 165 | defer func() { 166 | if err := recover(); err != nil { 167 | re = false 168 | } 169 | }() 170 | 171 | re = true 172 | if len(r.cread) < cap(r.cread) { 173 | pdata := make([]byte, n) 174 | copy(pdata, data) 175 | r.cread <- pdata 176 | } 177 | return 178 | } 179 | 180 | var udpMap map[string]*udpMsgQueHelper = map[string]*udpMsgQueHelper{} 181 | var udpMapLock sync.Mutex 182 | 183 | func (r *udpMsgQue) listenTrue() { 184 | data := make([]byte, 1<<16) 185 | for !r.IsStop() { 186 | r.Lock() 187 | n, addr, err := r.conn.ReadFromUDP(data) 188 | r.Unlock() 189 | if err != nil { 190 | if err.(net.Error).Timeout() { 191 | continue 192 | } 193 | break 194 | } 195 | 196 | if n <= 0 { 197 | continue 198 | } 199 | 200 | addrStr := addr.String() 201 | udpMapLock.Lock() 202 | helper, ok := udpMap[addrStr] 203 | if !ok { 204 | helper = &udpMsgQueHelper{null: true} 205 | udpMap[addrStr] = helper 206 | } 207 | udpMapLock.Unlock() 208 | 209 | if helper.null { 210 | helper.Lock() 211 | if atomic.CompareAndSwapInt32(&helper.init, 0, 1) { 212 | helper.udpMsgQue = newUdpAccept(r.conn, r.msgTyp, r.handler, r.parserFactory, addr) 213 | helper.null = false 214 | } 215 | helper.Unlock() 216 | } 217 | 218 | if !helper.sendRead(data, n) { 219 | LogError("drop msg because msgque full msgqueid:%v", helper.id) 220 | } 221 | } 222 | } 223 | 224 | func (r *udpMsgQue) listen() { 225 | for i := 0; i < Config.UdpServerGoCnt; i++ { 226 | Go(func() { 227 | r.listenTrue() 228 | }) 229 | } 230 | c := make(chan struct{}) 231 | Go2(func(cstop chan struct{}) { 232 | select { 233 | case <-cstop: 234 | case <-c: 235 | } 236 | r.conn.Close() 237 | }) 238 | r.listenTrue() 239 | close(c) 240 | r.Stop() 241 | } 242 | 243 | func newUdpAccept(conn *net.UDPConn, msgtyp MsgType, handler IMsgHandler, parser IParserFactory, addr *net.UDPAddr) *udpMsgQue { 244 | msgque := udpMsgQue{ 245 | msgQue: msgQue{ 246 | id: atomic.AddUint32(&msgqueId, 1), 247 | cwrite: make(chan *Message, 64), 248 | msgTyp: msgtyp, 249 | handler: handler, 250 | available: true, 251 | timeout: DefMsgQueTimeout, 252 | connTyp: ConnTypeAccept, 253 | gmsgId: gmsgId, 254 | parserFactory: parser, 255 | lastTick: Timestamp, 256 | }, 257 | conn: conn, 258 | cread: make(chan []byte, 64), 259 | addr: addr, 260 | } 261 | if parser != nil { 262 | msgque.parser = parser.Get() 263 | } 264 | msgqueMapSync.Lock() 265 | msgqueMap[msgque.id] = &msgque 266 | msgqueMapSync.Unlock() 267 | 268 | Go(func() { 269 | LogInfo("process read for msgque:%d", msgque.id) 270 | msgque.read() 271 | LogInfo("process read end for msgque:%d", msgque.id) 272 | }) 273 | Go(func() { 274 | LogInfo("process write for msgque:%d", msgque.id) 275 | msgque.write() 276 | LogInfo("process write end for msgque:%d", msgque.id) 277 | }) 278 | 279 | LogInfo("new msgque id:%d from addr:%s", msgque.id, addr.String()) 280 | return &msgque 281 | } 282 | 283 | func newUdpListen(conn *net.UDPConn, msgtyp MsgType, handler IMsgHandler, parser IParserFactory, addr string) *udpMsgQue { 284 | msgque := udpMsgQue{ 285 | msgQue: msgQue{ 286 | id: atomic.AddUint32(&msgqueId, 1), 287 | msgTyp: msgtyp, 288 | handler: handler, 289 | available: true, 290 | parserFactory: parser, 291 | connTyp: ConnTypeListen, 292 | }, 293 | conn: conn, 294 | } 295 | conn.SetReadBuffer(1 << 24) 296 | conn.SetWriteBuffer(1 << 24) 297 | msgqueMapSync.Lock() 298 | msgqueMap[msgque.id] = &msgque 299 | msgqueMapSync.Unlock() 300 | LogInfo("new udp listen id:%d addr:%s", msgque.id, addr) 301 | return &msgque 302 | } 303 | -------------------------------------------------------------------------------- /db_redis.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "io" 5 | "net" 6 | "strings" 7 | "sync" 8 | "sync/atomic" 9 | 10 | "github.com/go-redis/redis" 11 | ) 12 | 13 | type RedisConfig struct { 14 | Addr string 15 | Passwd string 16 | PoolSize int 17 | } 18 | 19 | type Redis struct { 20 | *redis.Client 21 | pubsub *redis.PubSub 22 | conf *RedisConfig 23 | manager *RedisManager 24 | } 25 | 26 | func (r *Redis) ScriptStr(cmd int, keys []string, args ...interface{}) (string, error) { 27 | data, err := r.Script(cmd, keys, args...) 28 | if err != nil { 29 | LogError("redis script failed err:%v", err) 30 | return "", ErrDBErr 31 | } 32 | errcode, ok := data.(int64) 33 | if ok { 34 | return "", GetError(uint16(errcode)) 35 | } 36 | if data == nil { 37 | return "", nil 38 | } 39 | str, ok := data.(string) 40 | if !ok { 41 | return "", ErrDBDataType 42 | } 43 | 44 | return str, nil 45 | } 46 | 47 | func (r *Redis) ScriptStrArray(cmd int, keys []string, args ...interface{}) ([]string, error) { 48 | data, err := r.Script(cmd, keys, args...) 49 | if err != nil { 50 | LogError("redis script failed err:%v", err) 51 | return nil, ErrDBErr 52 | } 53 | errcode, ok := data.(int64) 54 | if ok { 55 | return nil, GetError(uint16(errcode)) 56 | } 57 | 58 | iArray, ok := data.([]interface{}) 59 | if !ok { 60 | return nil, ErrDBDataType 61 | } 62 | 63 | strArray := []string{} 64 | for _, v := range iArray { 65 | if v == nil { 66 | strArray = append(strArray, "") 67 | } else if str, ok := v.(string); ok { 68 | strArray = append(strArray, str) 69 | } else { 70 | return nil, ErrDBDataType 71 | } 72 | } 73 | 74 | return strArray, nil 75 | } 76 | 77 | func (r *Redis) ScriptInt64(cmd int, keys []string, args ...interface{}) (int64, error) { 78 | data, err := r.Script(cmd, keys, args...) 79 | if err != nil { 80 | LogError("redis script failed err:%v", err) 81 | return 0, ErrDBErr 82 | } 83 | if data == nil { 84 | return 0, nil 85 | } 86 | code, ok := data.(int64) 87 | if ok { 88 | return code, nil 89 | } 90 | return 0, ErrDBDataType 91 | } 92 | 93 | func (r *Redis) Script(cmd int, keys []string, args ...interface{}) (interface{}, error) { 94 | var err error = ErrDBErr 95 | var re interface{} 96 | hashStr, ok := scriptHashMap.Load(cmd) 97 | if ok { 98 | re, err = r.EvalSha(hashStr.(string), keys, args...).Result() 99 | } 100 | if RedisError(err) { 101 | scriptStr, ok := scriptMap.Load(cmd) 102 | if !ok { 103 | LogError("redis script error cmd not found cmd:%v", cmd) 104 | return nil, ErrDBErr 105 | } 106 | cmdStr, _ := scriptCommitMap.Load(cmd) 107 | if strings.HasPrefix(err.Error(), "NOSCRIPT ") || err == ErrDBErr { 108 | LogInfo("try reload redis script %v", cmdStr.(string)) 109 | hashStr, err = r.ScriptLoad(scriptStr.(string)).Result() 110 | if err != nil { 111 | LogError("redis script load cmd:%v errstr:%s", cmdStr.(string), err) 112 | return nil, ErrDBErr 113 | } 114 | scriptHashMap.Store(cmd, hashStr.(string)) 115 | re, err = r.EvalSha(hashStr.(string), keys, args...).Result() 116 | if !RedisError(err) { 117 | return re, nil 118 | } 119 | } 120 | LogError("redis script error cmd:%v errstr:%s", cmdStr.(string), err) 121 | return nil, ErrDBErr 122 | } 123 | 124 | return re, nil 125 | } 126 | 127 | type RedisManager struct { 128 | dbs map[int]*Redis 129 | subMap map[string]*Redis 130 | channels []string 131 | fun func(channel, data string) 132 | lock sync.RWMutex 133 | } 134 | 135 | func (r *RedisManager) GetLen() int { 136 | return len(r.dbs) 137 | } 138 | 139 | func (r *RedisManager) GetByRid(rid int) *Redis { 140 | r.lock.RLock() 141 | db := r.dbs[rid] 142 | r.lock.RUnlock() 143 | return db 144 | } 145 | 146 | func (r *RedisManager) GetGlobal() *Redis { 147 | return r.GetByRid(0) 148 | } 149 | 150 | func (r *RedisManager) Sub(fun func(channel, data string), channels ...string) { 151 | r.lock.Lock() 152 | defer r.lock.Unlock() 153 | r.channels = channels 154 | r.fun = fun 155 | for _, v := range r.subMap { 156 | if v.pubsub != nil { 157 | v.pubsub.Close() 158 | } 159 | pubsub := v.Subscribe(channels...) 160 | v.pubsub = pubsub 161 | LogInfo("[redis]config:%v, subscribe channel:%v", v.conf, channels) 162 | goForRedis(func() { 163 | for IsRuning() { 164 | msg, err := pubsub.ReceiveMessage() 165 | if err == nil { 166 | Go(func() { fun(msg.Channel, msg.Payload) }) 167 | } else if _, ok := err.(net.Error); !ok { 168 | if err.Error() != "redis: reply is empty" { 169 | if !IsStop() { 170 | LogFatal("[redis]pubsub broken err:%v", err) 171 | } 172 | break 173 | } 174 | } 175 | } 176 | }) 177 | } 178 | } 179 | 180 | func (r *RedisManager) Exist(id int) bool { 181 | r.lock.Lock() 182 | _, ok := r.dbs[id] 183 | r.lock.Unlock() 184 | return ok 185 | } 186 | 187 | func (r *RedisManager) Add(id int, conf *RedisConfig) { 188 | r.lock.Lock() 189 | defer r.lock.Unlock() 190 | LogInfo("new redis id:%v conf:%#v", id, conf) 191 | if _, ok := r.dbs[id]; ok { 192 | LogError("redis already have id:%v", id) 193 | return 194 | } 195 | 196 | re := &Redis{ 197 | Client: redis.NewClient(&redis.Options{ 198 | Addr: conf.Addr, 199 | Password: conf.Passwd, 200 | PoolSize: conf.PoolSize, 201 | }), 202 | conf: conf, 203 | manager: r, 204 | } 205 | 206 | re.WrapProcess(func(oldProcess func(cmd redis.Cmder) error) func(cmd redis.Cmder) error { 207 | return func(cmd redis.Cmder) error { 208 | err := oldProcess(cmd) 209 | if err != nil { 210 | _, retry := err.(net.Error) 211 | if !retry { 212 | retry = err == io.EOF 213 | } 214 | if retry { 215 | err = oldProcess(cmd) 216 | } 217 | } 218 | return err 219 | } 220 | }) 221 | 222 | if v, ok := r.subMap[conf.Addr]; !ok { 223 | r.subMap[conf.Addr] = re 224 | if len(r.channels) > 0 { 225 | pubsub := re.Subscribe(r.channels...) 226 | re.pubsub = pubsub 227 | LogInfo("[redis]config:%v, subscribe channel:%v", v.conf, r.channels) 228 | goForRedis(func() { 229 | for IsRuning() { 230 | msg, err := pubsub.ReceiveMessage() 231 | if err == nil { 232 | Go(func() { r.fun(msg.Channel, msg.Payload) }) 233 | } else if _, ok := err.(net.Error); !ok && IsRuning() { 234 | if err.Error() != "redis: reply is empty" { 235 | LogFatal("[redis]pubsub broken err:%v", err) 236 | break 237 | } 238 | } 239 | } 240 | }) 241 | } 242 | } 243 | r.dbs[id] = re 244 | } 245 | 246 | func (r *RedisManager) close() { 247 | for _, v := range r.dbs { 248 | if v.pubsub != nil { 249 | v.pubsub.Close() 250 | } 251 | v.Close() 252 | } 253 | } 254 | 255 | var ( 256 | scriptMap = sync.Map{} //map[int]string{} 257 | scriptCommitMap = sync.Map{} //map[int]string{} 258 | scriptHashMap = sync.Map{} //map[int]string{} 259 | scriptIndex int32 = 0 260 | ) 261 | 262 | func NewRedisScript(commit, str string) int { 263 | cmd := int(atomic.AddInt32(&scriptIndex, 1)) 264 | scriptMap.Store(cmd, str) 265 | scriptCommitMap.Store(cmd, commit) 266 | return cmd 267 | } 268 | 269 | func GetRedisScript(cmd int) string { 270 | if s, ok := scriptMap.Load(cmd); ok { 271 | return s.(string) 272 | } 273 | return "" 274 | } 275 | 276 | var redisManagers []*RedisManager 277 | 278 | func NewRedisManager(conf *RedisConfig) *RedisManager { 279 | redisManager := &RedisManager{ 280 | subMap: map[string]*Redis{}, 281 | dbs: map[int]*Redis{}, 282 | } 283 | 284 | redisManager.Add(0, conf) 285 | redisManagers = append(redisManagers, redisManager) 286 | return redisManager 287 | } 288 | 289 | func RedisError(err error) bool { 290 | if err == redis.Nil { 291 | return false 292 | } 293 | return err != nil 294 | } 295 | -------------------------------------------------------------------------------- /msgque_ws.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "net/http" 5 | "sync" 6 | "sync/atomic" 7 | "time" 8 | 9 | "github.com/gorilla/websocket" 10 | ) 11 | 12 | type wsMsgQue struct { 13 | msgQue 14 | conn *websocket.Conn 15 | upgrader *websocket.Upgrader 16 | addr string 17 | url string 18 | wait sync.WaitGroup 19 | connecting int32 20 | listener *http.Server 21 | } 22 | 23 | func (r *wsMsgQue) GetNetType() NetType { 24 | return NetTypeWs 25 | } 26 | 27 | func (r *wsMsgQue) Stop() { 28 | if atomic.CompareAndSwapInt32(&r.stop, 0, 1) { 29 | Go(func() { 30 | if r.init { 31 | r.handler.OnDelMsgQue(r) 32 | } 33 | r.available = false 34 | r.baseStop() 35 | }) 36 | } 37 | } 38 | 39 | func (r *wsMsgQue) IsStop() bool { 40 | if r.stop == 0 { 41 | if IsStop() { 42 | r.Stop() 43 | } 44 | } 45 | return r.stop == 1 46 | } 47 | 48 | func (r *wsMsgQue) LocalAddr() string { 49 | if r.conn != nil { 50 | return r.conn.LocalAddr().String() 51 | } 52 | return "" 53 | } 54 | 55 | func (r *wsMsgQue) RemoteAddr() string { 56 | if r.realRemoteAddr != "" { 57 | return r.realRemoteAddr 58 | } 59 | if r.conn != nil { 60 | return r.conn.RemoteAddr().String() 61 | } 62 | return "" 63 | } 64 | 65 | func (r *wsMsgQue) readCmd() { 66 | for !r.IsStop() { 67 | _, data, err := r.conn.ReadMessage() 68 | if err != nil { 69 | LogError("msgque:%v recv data err:%v", r.id, err) 70 | break 71 | } 72 | if !r.processMsg(r, &Message{Data: data}) { 73 | break 74 | } 75 | r.lastTick = Timestamp 76 | } 77 | } 78 | 79 | func (r *wsMsgQue) writeCmd() { 80 | var m *Message 81 | gm := r.getGMsg(false) 82 | tick := time.NewTimer(time.Second * time.Duration(r.timeout)) 83 | for !r.IsStop() || m != nil { 84 | if m == nil { 85 | select { 86 | case <-stopChanForGo: 87 | case m = <-r.cwrite: 88 | case <-gm.c: 89 | if gm.fun == nil || gm.fun(r) { 90 | m = gm.msg 91 | } 92 | gm = r.getGMsg(true) 93 | case <-tick.C: 94 | if r.isTimeout(tick) { 95 | r.Stop() 96 | } 97 | } 98 | } 99 | 100 | if m == nil || m.Data == nil { 101 | m = nil 102 | continue 103 | } 104 | err := r.conn.WriteMessage(websocket.BinaryMessage, m.Data) 105 | if err != nil { 106 | LogError("msgque write id:%v err:%v", r.id, err) 107 | break 108 | } 109 | m = nil 110 | r.lastTick = Timestamp 111 | } 112 | tick.Stop() 113 | } 114 | 115 | func (r *wsMsgQue) read() { 116 | defer func() { 117 | if err := recover(); err != nil { 118 | LogError("msgque read panic id:%v err:%v", r.id, err.(error)) 119 | LogStack() 120 | } 121 | r.Stop() 122 | }() 123 | 124 | r.readCmd() 125 | } 126 | 127 | func (r *wsMsgQue) write() { 128 | defer func() { 129 | if err := recover(); err != nil { 130 | LogError("msgque write panic id:%v err:%v", r.id, err.(error)) 131 | LogStack() 132 | } 133 | if r.conn != nil { 134 | r.conn.Close() 135 | } 136 | r.Stop() 137 | }() 138 | 139 | r.writeCmd() 140 | } 141 | 142 | func (r *wsMsgQue) listen() { 143 | Go2(func(cstop chan struct{}) { 144 | select { 145 | case <-cstop: 146 | } 147 | r.listener.Close() 148 | }) 149 | 150 | r.upgrader = &websocket.Upgrader{ 151 | ReadBufferSize: 4096, 152 | WriteBufferSize: 4096, 153 | CheckOrigin: func(r *http.Request) bool { 154 | return true 155 | }, 156 | } 157 | 158 | http.HandleFunc(r.url, func(hw http.ResponseWriter, hr *http.Request) { 159 | c, err := r.upgrader.Upgrade(hw, hr, nil) 160 | if err != nil { 161 | if stop == 0 && r.stop == 0 { 162 | LogError("accept failed msgque:%v err:%v", r.id, err) 163 | } 164 | } else { 165 | Go(func() { 166 | msgque := newWsAccept(c, r.msgTyp, r.handler, r.parserFactory) 167 | if r.handler.OnNewMsgQue(msgque) { 168 | msgque.init = true 169 | msgque.available = true 170 | Go(func() { 171 | LogInfo("process read for msgque:%d", msgque.id) 172 | msgque.read() 173 | LogInfo("process read end for msgque:%d", msgque.id) 174 | }) 175 | Go(func() { 176 | LogInfo("process write for msgque:%d", msgque.id) 177 | msgque.write() 178 | LogInfo("process write end for msgque:%d", msgque.id) 179 | }) 180 | } else { 181 | msgque.Stop() 182 | } 183 | }) 184 | } 185 | }) 186 | 187 | if Config.EnableWss { 188 | if Config.SSLCrtPath != "" && Config.SSLKeyPath != "" { 189 | r.listener.ListenAndServeTLS(Config.SSLCrtPath, Config.SSLKeyPath) 190 | } else { 191 | LogError("start wss failed ssl path not set please set now auto change to ws") 192 | r.listener.ListenAndServe() 193 | } 194 | } else { 195 | r.listener.ListenAndServe() 196 | } 197 | } 198 | func (r *wsMsgQue) connect() { 199 | LogInfo("connect to addr:%s msgque:%d",r.addr, r.id) 200 | c, _, err := websocket.DefaultDialer.Dial(r.addr, nil) 201 | if err != nil { 202 | LogInfo("connect to addr:%s failed msgque:%d err:%v ", r.addr, r.id, err) 203 | r.handler.OnConnectComplete(r, false) 204 | atomic.CompareAndSwapInt32(&r.connecting, 1, 0) 205 | r.Stop() 206 | } else { 207 | r.conn = c 208 | r.available = true 209 | LogInfo("connect to addr:%s ok msgque:%d", r.addr, r.id) 210 | if r.handler.OnConnectComplete(r, true) { 211 | atomic.CompareAndSwapInt32(&r.connecting, 1, 0) 212 | Go(func() { 213 | LogInfo("process read for msgque:%d", r.id) 214 | r.read() 215 | LogInfo("process read end for msgque:%d", r.id) 216 | }) 217 | Go(func() { 218 | LogInfo("process write for msgque:%d", r.id) 219 | r.write() 220 | LogInfo("process write end for msgque:%d", r.id) 221 | }) 222 | } else { 223 | atomic.CompareAndSwapInt32(&r.connecting, 1, 0) 224 | r.Stop() 225 | } 226 | } 227 | } 228 | 229 | 230 | func (r *wsMsgQue) Reconnect(t int) { 231 | if IsStop() { 232 | return 233 | } 234 | if r.conn != nil { 235 | if r.stop == 0 { 236 | return 237 | } 238 | } 239 | 240 | if !atomic.CompareAndSwapInt32(&r.connecting, 0, 1) { 241 | return 242 | } 243 | 244 | if r.init { 245 | if t < 1 { 246 | t = 1 247 | } 248 | } 249 | r.init = true 250 | Go(func() { 251 | if len(r.cwrite) == 0 { 252 | r.cwrite <- nil 253 | } 254 | r.wait.Wait() 255 | if t > 0 { 256 | SetTimeout(t*1000, func(arg ...interface{}) int { 257 | r.stop = 0 258 | r.connect() 259 | return 0 260 | }) 261 | } else { 262 | r.stop = 0 263 | r.connect() 264 | } 265 | 266 | }) 267 | } 268 | 269 | func newWsConn(addr string, conn *websocket.Conn, msgtyp MsgType, handler IMsgHandler, parser IParserFactory, user interface{}) *wsMsgQue { 270 | msgque := wsMsgQue{ 271 | msgQue: msgQue{ 272 | id: atomic.AddUint32(&msgqueId, 1), 273 | cwrite: make(chan *Message, 64), 274 | msgTyp: msgtyp, 275 | handler: handler, 276 | timeout: DefMsgQueTimeout, 277 | connTyp: ConnTypeConn, 278 | gmsgId: gmsgId, 279 | parserFactory: parser, 280 | lastTick: Timestamp, 281 | user: user, 282 | }, 283 | conn: conn, 284 | addr: addr, 285 | } 286 | if parser != nil { 287 | msgque.parser = parser.Get() 288 | } 289 | msgqueMapSync.Lock() 290 | msgqueMap[msgque.id] = &msgque 291 | msgqueMapSync.Unlock() 292 | LogInfo("new msgque id:%d connect to addr:%s", msgque.id, addr) 293 | return &msgque 294 | } 295 | 296 | func newWsAccept(conn *websocket.Conn, msgtyp MsgType, handler IMsgHandler, parser IParserFactory) *wsMsgQue { 297 | msgque := wsMsgQue{ 298 | msgQue: msgQue{ 299 | id: atomic.AddUint32(&msgqueId, 1), 300 | cwrite: make(chan *Message, 64), 301 | msgTyp: msgtyp, 302 | handler: handler, 303 | timeout: DefMsgQueTimeout, 304 | connTyp: ConnTypeAccept, 305 | gmsgId: gmsgId, 306 | lastTick: Timestamp, 307 | parserFactory: parser, 308 | }, 309 | conn: conn, 310 | } 311 | if parser != nil { 312 | msgque.parser = parser.Get() 313 | } 314 | msgqueMapSync.Lock() 315 | msgqueMap[msgque.id] = &msgque 316 | msgqueMapSync.Unlock() 317 | LogInfo("new msgque id:%d from addr:%s", msgque.id, conn.RemoteAddr().String()) 318 | return &msgque 319 | } 320 | 321 | func newWsListen(addr, url string, msgtyp MsgType, handler IMsgHandler, parser IParserFactory) *wsMsgQue { 322 | msgque := wsMsgQue{ 323 | msgQue: msgQue{ 324 | id: atomic.AddUint32(&msgqueId, 1), 325 | msgTyp: msgtyp, 326 | handler: handler, 327 | parserFactory: parser, 328 | connTyp: ConnTypeListen, 329 | }, 330 | addr: addr, 331 | url: url, 332 | listener: &http.Server{Addr: addr}, 333 | } 334 | 335 | msgqueMapSync.Lock() 336 | msgqueMap[msgque.id] = &msgque 337 | msgqueMapSync.Unlock() 338 | LogInfo("new ws listen id:%d addr:%s url:%s", msgque.id, addr, url) 339 | return &msgque 340 | } 341 | -------------------------------------------------------------------------------- /log.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "path" 8 | "path/filepath" 9 | "runtime" 10 | "strings" 11 | "sync/atomic" 12 | "time" 13 | ) 14 | 15 | type ILogger interface { 16 | Write(str string) 17 | } 18 | 19 | type ConsoleLogger struct { 20 | Ln bool 21 | } 22 | 23 | func (r *ConsoleLogger) Write(str string) { 24 | if r.Ln { 25 | fmt.Println(str) 26 | } else { 27 | fmt.Print(str) 28 | } 29 | } 30 | 31 | type OnFileLogFull func(path string) 32 | type OnFileLogTimeout func(path string) int 33 | type OnFileRename func(dirName, fileName, extName string) string 34 | type FileLogger struct { 35 | Path string 36 | Ln bool 37 | Timeout int //0表示不设置, 单位s 38 | MaxSize int //0表示不限制,最大大小 39 | OnFull OnFileLogFull 40 | OnTimeout OnFileLogTimeout 41 | OnRenameFile OnFileRename 42 | 43 | size int 44 | file *os.File 45 | filename string 46 | extname string 47 | dirname string 48 | } 49 | 50 | func (r *FileLogger) Write(str string) { 51 | if r.file == nil { 52 | return 53 | } 54 | 55 | newsize := r.size 56 | if r.Ln { 57 | newsize += len(str) + 1 58 | } else { 59 | newsize += len(str) 60 | } 61 | 62 | if r.MaxSize > 0 && newsize >= r.MaxSize { 63 | r.file.Close() 64 | r.file = nil 65 | newpath := r.dirname + "/" + r.filename + fmt.Sprintf("_%v", Date()) + r.extname 66 | if r.OnRenameFile != nil { 67 | newpath = r.OnRenameFile(r.dirname+"/", r.filename, r.extname) 68 | } 69 | os.Rename(r.Path, newpath) 70 | file, err := os.OpenFile(r.Path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0644) 71 | if err == nil { 72 | r.file = file 73 | } 74 | r.size = 0 75 | if r.OnFull != nil { 76 | r.OnFull(newpath) 77 | } 78 | } 79 | 80 | if r.file == nil { 81 | return 82 | } 83 | 84 | if r.Ln { 85 | r.file.WriteString(str) 86 | r.file.WriteString("\n") 87 | r.size += len(str) + 1 88 | } else { 89 | r.file.WriteString(str) 90 | r.size += len(str) 91 | } 92 | } 93 | 94 | type HttpLogger struct { 95 | Url string 96 | Get bool 97 | GetKey string 98 | Timeout int 99 | } 100 | 101 | func (r *HttpLogger) Write(str string) { 102 | if r.Url == "" { 103 | return 104 | } 105 | Go(func() { 106 | if r.Timeout == 0 { 107 | r.Timeout = 5 108 | } 109 | c := http.Client{ 110 | Timeout: time.Duration(r.Timeout) * time.Second, 111 | } 112 | var resp *http.Response 113 | if r.Get { 114 | if r.GetKey == "" { 115 | r.GetKey = "log" 116 | } 117 | resp, _ = c.Get(r.Url + "/?" + r.GetKey + "=" + str) 118 | } else { 119 | resp, _ = c.Post(r.Url, "application/x-www-form-urlencoded", strings.NewReader(str)) 120 | } 121 | 122 | if resp != nil && resp.Body != nil { 123 | resp.Body.Close() 124 | } 125 | }) 126 | } 127 | 128 | type LogLevel int 129 | 130 | const ( 131 | LogLevelTrace LogLevel = iota //跟踪信息 132 | LogLevelDebug //调试信息 133 | LogLevelInfo //资讯讯息 134 | LogLevelWarn //警告状况发生 135 | LogLevelError //一般错误,可能导致功能不正常 136 | LogLevelFatal //严重错误,会导致进程退出 137 | LogLevelAllOff //关闭所有日志 138 | ) 139 | 140 | var LogLevelNameMap = map[string]LogLevel{ 141 | "trace": LogLevelTrace, 142 | "debug": LogLevelDebug, 143 | "info": LogLevelInfo, 144 | "warn": LogLevelWarn, 145 | "error": LogLevelError, 146 | "fatal": LogLevelFatal, 147 | "off": LogLevelAllOff, 148 | } 149 | 150 | type Log struct { 151 | logger [32]ILogger 152 | cwrite chan string 153 | ctimeout chan *FileLogger 154 | bufsize int 155 | stop int32 156 | preLoggerCount int32 157 | loggerCount int32 158 | level LogLevel 159 | callStackCnt int 160 | formatFunc func(level LogLevel, fileName string, line int, v ...interface{}) string 161 | } 162 | 163 | func (r *Log) initFileLogger(f *FileLogger) *FileLogger { 164 | if f.file == nil { 165 | f.Path, _ = filepath.Abs(f.Path) 166 | f.Path = StrReplace(f.Path, "\\", "/") 167 | f.dirname = path.Dir(f.Path) 168 | f.extname = path.Ext(f.Path) 169 | f.filename = filepath.Base(f.Path[0 : len(f.Path)-len(f.extname)]) 170 | os.MkdirAll(f.dirname, 0666) 171 | file, err := os.OpenFile(f.Path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) 172 | if err == nil { 173 | f.file = file 174 | info, err := f.file.Stat() 175 | if err != nil { 176 | return nil 177 | } 178 | 179 | f.size = int(info.Size()) 180 | if f.Timeout > 0 { 181 | SetTimeout(f.Timeout*1000, func(...interface{}) int { 182 | defer func() { recover() }() 183 | r.ctimeout <- f 184 | return 0 185 | }) 186 | } 187 | 188 | return f 189 | } 190 | } 191 | return nil 192 | } 193 | 194 | func (r *Log) start() { 195 | goForLog(func(cstop chan struct{}) { 196 | var i int32 197 | for !r.IsStop() { 198 | select { 199 | case s, ok := <-r.cwrite: 200 | if ok { 201 | for i = 0; i < r.loggerCount; i++ { 202 | r.logger[i].Write(s) 203 | } 204 | } 205 | case c, ok := <-r.ctimeout: 206 | if ok { 207 | c.file.Close() 208 | c.file = nil 209 | newpath := c.dirname + "/" + c.filename + fmt.Sprintf("_%v", Date()) + c.extname 210 | if c.OnRenameFile != nil { 211 | newpath = c.OnRenameFile(c.dirname+"/", c.filename, c.extname) 212 | } 213 | os.Rename(c.Path, newpath) 214 | file, err := os.OpenFile(c.Path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) 215 | if err == nil { 216 | c.file = file 217 | } 218 | 219 | c.size = 0 220 | if c.OnTimeout != nil { 221 | nc := c.OnTimeout(newpath) 222 | if nc > 0 { 223 | SetTimeout(nc*1000, func(...interface{}) int { 224 | defer func() { recover() }() 225 | r.ctimeout <- c 226 | return 0 227 | }) 228 | } 229 | } 230 | } 231 | case <-cstop: 232 | } 233 | } 234 | 235 | for s := range r.cwrite { 236 | for i = 0; i < r.loggerCount; i++ { 237 | r.logger[i].Write(s) 238 | } 239 | } 240 | 241 | // 关闭打开的文件fd 242 | for i = 0; i < r.loggerCount; i++ { 243 | if f, ok := r.logger[i].(*FileLogger); ok { 244 | if f.file != nil { 245 | f.file.Close() 246 | f.file = nil 247 | } 248 | } 249 | } 250 | }) 251 | } 252 | 253 | func (r *Log) Stop() { 254 | if atomic.CompareAndSwapInt32(&r.stop, 0, 1) { 255 | close(r.cwrite) 256 | close(r.ctimeout) 257 | } 258 | } 259 | 260 | func (r *Log) SetLogger(logger ILogger) bool { 261 | if r.preLoggerCount >= 31 { 262 | return false 263 | } 264 | if f, ok := logger.(*FileLogger); ok { 265 | if r.initFileLogger(f) == nil { 266 | return false 267 | } 268 | } 269 | r.logger[atomic.AddInt32(&r.preLoggerCount, 1)] = logger 270 | atomic.AddInt32(&r.loggerCount, 1) 271 | return true 272 | 273 | } 274 | func (r *Log) Level() LogLevel { 275 | return r.level 276 | } 277 | func (r *Log) SetLevel(level LogLevel) { 278 | r.level = level 279 | } 280 | func (r *Log) SetCallStackCnt(callStackCnt int) { 281 | r.callStackCnt = callStackCnt 282 | } 283 | func (r *Log) SetLevelByName(name string) bool { 284 | level, ok := LogLevelNameMap[name] 285 | if ok { 286 | r.SetLevel(level) 287 | } 288 | return ok 289 | } 290 | 291 | func isLogStop() bool { 292 | return stopForLog == 1 293 | } 294 | 295 | func (r *Log) IsStop() bool { 296 | if r.stop == 0 { 297 | if isLogStop() { 298 | r.Stop() 299 | } 300 | } 301 | return r.stop == 1 302 | } 303 | 304 | func (r *Log) SetFormatFunc(formatFunc func(level LogLevel, fileName string, line int, v ...interface{}) string) { 305 | r.formatFunc = formatFunc 306 | } 307 | 308 | func (r *Log) write(levstr string, level LogLevel, v ...interface{}) { 309 | defer func() { recover() }() 310 | if r.IsStop() { 311 | return 312 | } 313 | 314 | if r.formatFunc != nil { 315 | _, file, line, ok := runtime.Caller(r.callStackCnt) 316 | if ok { 317 | i := strings.LastIndex(file, "/") + 1 318 | if len(v) > 1 { 319 | r.cwrite <- r.formatFunc(level, string(([]byte(file))[i:]), line, v...) 320 | } else { 321 | r.cwrite <- r.formatFunc(level, string(([]byte(file))[i:]), line, v...) 322 | } 323 | } 324 | } else { 325 | prefix := levstr 326 | _, file, line, ok := runtime.Caller(r.callStackCnt) 327 | if ok { 328 | i := strings.LastIndex(file, "/") + 1 329 | prefix = fmt.Sprintf("[%s][%s][%s:%d]:", levstr, Date(), string(([]byte(file))[i:]), line) 330 | } 331 | if len(v) > 1 { 332 | r.cwrite <- prefix + fmt.Sprintf(v[0].(string), v[1:]...) 333 | } else { 334 | r.cwrite <- prefix + fmt.Sprint(v[0]) 335 | } 336 | } 337 | } 338 | 339 | func (r *Log) Trace(v ...interface{}) { 340 | if r.level <= LogLevelTrace { 341 | r.write("T", LogLevelTrace, v...) 342 | } 343 | } 344 | 345 | func (r *Log) Debug(v ...interface{}) { 346 | if r.level <= LogLevelDebug { 347 | r.write("D", LogLevelDebug, v...) 348 | } 349 | } 350 | 351 | func (r *Log) Info(v ...interface{}) { 352 | if r.level <= LogLevelInfo { 353 | r.write("I", LogLevelInfo, v...) 354 | } 355 | } 356 | 357 | func (r *Log) Warn(v ...interface{}) { 358 | if r.level <= LogLevelWarn { 359 | r.write("W", LogLevelWarn, v...) 360 | } 361 | } 362 | 363 | func (r *Log) Error(v ...interface{}) { 364 | if r.level <= LogLevelError { 365 | r.write("E", LogLevelError, v...) 366 | } 367 | } 368 | 369 | func (r *Log) Fatal(v ...interface{}) { 370 | if r.level <= LogLevelFatal { 371 | r.write("F", LogLevelFatal, v...) 372 | } 373 | } 374 | 375 | func (r *Log) Write(v ...interface{}) { 376 | defer func() { recover() }() 377 | if r.IsStop() { 378 | return 379 | } 380 | 381 | if len(v) > 1 { 382 | r.cwrite <- fmt.Sprintf(v[0].(string), v[1:]...) 383 | } else if len(v) > 0 { 384 | r.cwrite <- fmt.Sprint(v[0]) 385 | } 386 | } 387 | 388 | func NewLog(bufsize int, logger ...ILogger) *Log { 389 | log := &Log{ 390 | bufsize: bufsize, 391 | callStackCnt: 3, 392 | cwrite: make(chan string, bufsize), 393 | ctimeout: make(chan *FileLogger, 32), 394 | level: LogLevelDebug, 395 | preLoggerCount: -1, 396 | } 397 | for _, l := range logger { 398 | log.SetLogger(l) 399 | } 400 | log.start() 401 | return log 402 | } 403 | 404 | func LogTrace(v ...interface{}) { 405 | DefLog.Trace(v...) 406 | } 407 | 408 | func LogInfo(v ...interface{}) { 409 | DefLog.Info(v...) 410 | } 411 | 412 | func LogDebug(v ...interface{}) { 413 | DefLog.Debug(v...) 414 | } 415 | 416 | func LogError(v ...interface{}) { 417 | DefLog.Error(v...) 418 | } 419 | 420 | func LogFatal(v ...interface{}) { 421 | DefLog.Fatal(v...) 422 | } 423 | 424 | func LogWarn(v ...interface{}) { 425 | DefLog.Warn(v...) 426 | } 427 | 428 | func LogStack() { 429 | buf := make([]byte, 1<<12) 430 | LogError(string(buf[:runtime.Stack(buf, false)])) 431 | } 432 | 433 | func LogSimpleStack() string { 434 | _, file, line, _ := runtime.Caller(2) 435 | i := strings.LastIndex(file, "/") + 1 436 | i = strings.LastIndex((string)(([]byte(file))[:i-1]), "/") + 1 437 | 438 | return Sprintf("%s:%d", (string)(([]byte(file))[i:]), line) 439 | } 440 | -------------------------------------------------------------------------------- /msgque_tcp.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "net" 7 | "sync" 8 | "sync/atomic" 9 | "time" 10 | ) 11 | 12 | type tcpMsgQue struct { 13 | msgQue 14 | conn net.Conn //连接 15 | listener net.Listener //监听 16 | network string 17 | address string 18 | wait sync.WaitGroup 19 | connecting int32 20 | rawBuffer []byte 21 | } 22 | 23 | func (r *tcpMsgQue) SetCmdReadRaw() { 24 | r.rawBuffer = make([]byte, Config.ReadDataBuffer) 25 | } 26 | 27 | func (r *tcpMsgQue) GetNetType() NetType { 28 | return NetTypeTcp 29 | } 30 | func (r *tcpMsgQue) Stop() { 31 | if atomic.CompareAndSwapInt32(&r.stop, 0, 1) { 32 | Go(func() { 33 | if r.init { 34 | r.handler.OnDelMsgQue(r) 35 | if r.connecting == 1 { 36 | r.available = false 37 | return 38 | } 39 | } 40 | r.available = false 41 | r.baseStop() 42 | }) 43 | } 44 | } 45 | 46 | func (r *tcpMsgQue) IsStop() bool { 47 | if r.stop == 0 { 48 | if IsStop() { 49 | r.Stop() 50 | } 51 | } 52 | return r.stop == 1 53 | } 54 | 55 | func (r *tcpMsgQue) LocalAddr() string { 56 | if r.conn != nil { 57 | return r.conn.LocalAddr().String() 58 | } else if r.listener != nil { 59 | return r.listener.Addr().String() 60 | } 61 | return "" 62 | } 63 | 64 | func (r *tcpMsgQue) RemoteAddr() string { 65 | if r.realRemoteAddr != "" { 66 | return r.realRemoteAddr 67 | } 68 | if r.conn != nil { 69 | return r.conn.RemoteAddr().String() 70 | } 71 | return r.address 72 | } 73 | 74 | func (r *tcpMsgQue) readMsg() { 75 | headData := make([]byte, MsgHeadSize) 76 | var data []byte 77 | var head *MessageHead 78 | 79 | for !r.IsStop() { 80 | if head == nil { 81 | _, err := io.ReadFull(r.conn, headData) 82 | if err != nil { 83 | if err != io.EOF { 84 | LogDebug("msgque:%v recv data err:%v", r.id, err) 85 | } 86 | break 87 | } 88 | if head = NewMessageHead(headData); head == nil { 89 | LogError("msgque:%v read msg head failed", r.id) 90 | break 91 | } 92 | if head.Len == 0 { 93 | if !r.processMsg(r, &Message{Head: head}) { 94 | LogError("msgque:%v process msg cmd:%v act:%v", r.id, head.Cmd, head.Act) 95 | break 96 | } 97 | head = nil 98 | } else { 99 | data = make([]byte, head.Len) 100 | } 101 | } else { 102 | _, err := io.ReadFull(r.conn, data) 103 | if err != nil { 104 | LogError("msgque:%v recv data err:%v", r.id, err) 105 | break 106 | } 107 | 108 | if !r.processMsg(r, &Message{Head: head, Data: data}) { 109 | LogError("msgque:%v process msg cmd:%v act:%v", r.id, head.Cmd, head.Act) 110 | break 111 | } 112 | 113 | head = nil 114 | data = nil 115 | } 116 | r.lastTick = Timestamp 117 | } 118 | } 119 | 120 | func (r *tcpMsgQue) writeMsg() { 121 | var m *Message 122 | var data []byte 123 | gm := r.getGMsg(false) 124 | writeCount := 0 125 | tick := time.NewTimer(time.Second * time.Duration(r.timeout)) 126 | for !r.IsStop() || m != nil { 127 | if m == nil { 128 | select { 129 | case <-stopChanForGo: 130 | case m = <-r.cwrite: 131 | if m != nil { 132 | data = m.Bytes() 133 | } 134 | case <-gm.c: 135 | if gm.fun == nil || gm.fun(r) { 136 | m = gm.msg 137 | data = m.Bytes() 138 | } 139 | gm = r.getGMsg(true) 140 | case <-tick.C: 141 | if r.isTimeout(tick) { 142 | r.Stop() 143 | } 144 | } 145 | } 146 | 147 | if m == nil { 148 | continue 149 | } 150 | 151 | if writeCount < len(data) { 152 | n, err := r.conn.Write(data[writeCount:]) 153 | if err != nil { 154 | LogError("msgque write id:%v err:%v", r.id, err) 155 | break 156 | } 157 | writeCount += n 158 | } 159 | 160 | if writeCount == len(data) { 161 | writeCount = 0 162 | m = nil 163 | } 164 | r.lastTick = Timestamp 165 | } 166 | tick.Stop() 167 | } 168 | 169 | func (r *tcpMsgQue) readCmd() { 170 | reader := bufio.NewReader(r.conn) 171 | var err error 172 | var len int 173 | var data []byte 174 | for !r.IsStop() { 175 | if r.rawBuffer != nil { 176 | len, err = reader.Read(r.rawBuffer) 177 | if err == nil && len > 0 { 178 | data = make([]byte, len) 179 | copy(data, r.rawBuffer) 180 | } 181 | } else { 182 | data, err = reader.ReadBytes('\n') 183 | } 184 | if err != nil { 185 | break 186 | } 187 | if !r.processMsg(r, &Message{Data: data}) { 188 | break 189 | } 190 | r.lastTick = Timestamp 191 | } 192 | } 193 | 194 | func (r *tcpMsgQue) writeCmd() { 195 | var m *Message 196 | gm := r.getGMsg(false) 197 | writeCount := 0 198 | tick := time.NewTimer(time.Second * time.Duration(r.timeout)) 199 | for !r.IsStop() || m != nil { 200 | if m == nil { 201 | select { 202 | case <-stopChanForGo: 203 | case m = <-r.cwrite: 204 | case <-gm.c: 205 | if gm.fun == nil || gm.fun(r) { 206 | m = gm.msg 207 | } 208 | gm = r.getGMsg(true) 209 | case <-tick.C: 210 | if r.isTimeout(tick) { 211 | r.Stop() 212 | } 213 | } 214 | } 215 | 216 | if m == nil || m.Data == nil { 217 | m = nil 218 | continue 219 | } 220 | n, err := r.conn.Write(m.Data[writeCount:]) 221 | if err != nil { 222 | LogError("msgque write id:%v err:%v", r.id, err) 223 | break 224 | } 225 | writeCount += n 226 | if writeCount == len(m.Data) { 227 | writeCount = 0 228 | m = nil 229 | } 230 | r.lastTick = Timestamp 231 | } 232 | tick.Stop() 233 | } 234 | 235 | func (r *tcpMsgQue) read() { 236 | defer func() { 237 | r.wait.Done() 238 | if err := recover(); err != nil { 239 | LogError("msgque read panic id:%v err:%v", r.id, err.(error)) 240 | LogStack() 241 | } 242 | r.Stop() 243 | }() 244 | 245 | r.wait.Add(1) 246 | if r.msgTyp == MsgTypeCmd { 247 | r.readCmd() 248 | } else { 249 | r.readMsg() 250 | } 251 | } 252 | 253 | func (r *tcpMsgQue) write() { 254 | defer func() { 255 | r.wait.Done() 256 | if err := recover(); err != nil { 257 | LogError("msgque write panic id:%v err:%v", r.id, err.(error)) 258 | LogStack() 259 | } 260 | if r.conn != nil { 261 | r.conn.Close() 262 | } 263 | r.Stop() 264 | }() 265 | r.wait.Add(1) 266 | if r.msgTyp == MsgTypeCmd { 267 | r.writeCmd() 268 | } else { 269 | r.writeMsg() 270 | } 271 | } 272 | 273 | func (r *tcpMsgQue) listen() { 274 | c := make(chan struct{}) 275 | Go2(func(cstop chan struct{}) { 276 | select { 277 | case <-cstop: 278 | case <-c: 279 | } 280 | r.listener.Close() 281 | }) 282 | for !r.IsStop() { 283 | c, err := r.listener.Accept() 284 | if err != nil { 285 | if stop == 0 && r.stop == 0 { 286 | LogError("accept failed msgque:%v err:%v", r.id, err) 287 | } 288 | break 289 | } else { 290 | Go(func() { 291 | msgque := newTcpAccept(c, r.msgTyp, r.handler, r.parserFactory) 292 | if r.handler.OnNewMsgQue(msgque) { 293 | msgque.init = true 294 | msgque.available = true 295 | Go(func() { 296 | LogInfo("process read for msgque:%d", msgque.id) 297 | msgque.read() 298 | LogInfo("process read end for msgque:%d", msgque.id) 299 | }) 300 | Go(func() { 301 | LogInfo("process write for msgque:%d", msgque.id) 302 | msgque.write() 303 | LogInfo("process write end for msgque:%d", msgque.id) 304 | }) 305 | } else { 306 | msgque.Stop() 307 | } 308 | }) 309 | } 310 | } 311 | 312 | close(c) 313 | r.Stop() 314 | } 315 | 316 | func (r *tcpMsgQue) connect() { 317 | LogDebug("connect to addr:%s msgque:%d", r.address, r.id) 318 | c, err := net.DialTimeout(r.network, r.address, time.Second) 319 | if err != nil { 320 | LogError("connect to addr:%s failed msgque:%d err:%v", r.address, r.id, err) 321 | r.handler.OnConnectComplete(r, false) 322 | atomic.CompareAndSwapInt32(&r.connecting, 1, 0) 323 | r.Stop() 324 | } else { 325 | r.conn = c 326 | r.available = true 327 | LogDebug("connect to addr:%s ok msgque:%d", r.address, r.id) 328 | if r.handler.OnConnectComplete(r, true) { 329 | atomic.CompareAndSwapInt32(&r.connecting, 1, 0) 330 | Go(func() { 331 | LogInfo("process read for msgque:%d", r.id) 332 | r.read() 333 | LogInfo("process read end for msgque:%d", r.id) 334 | }) 335 | Go(func() { 336 | LogInfo("process write for msgque:%d", r.id) 337 | r.write() 338 | LogInfo("process write end for msgque:%d", r.id) 339 | }) 340 | } else { 341 | atomic.CompareAndSwapInt32(&r.connecting, 1, 0) 342 | r.Stop() 343 | } 344 | } 345 | } 346 | 347 | func (r *tcpMsgQue) Reconnect(t int) { 348 | if IsStop() { 349 | return 350 | } 351 | if r.conn != nil { 352 | if r.stop == 0 { 353 | return 354 | } 355 | } 356 | 357 | if !atomic.CompareAndSwapInt32(&r.connecting, 0, 1) { 358 | return 359 | } 360 | 361 | if r.init { 362 | if t < 1 { 363 | t = 1 364 | } 365 | } 366 | r.init = true 367 | Go(func() { 368 | if len(r.cwrite) == 0 { 369 | r.cwrite <- nil 370 | } 371 | r.wait.Wait() 372 | if t > 0 { 373 | SetTimeout(t*1000, func(arg ...interface{}) int { 374 | r.stop = 0 375 | r.connect() 376 | return 0 377 | }) 378 | } else { 379 | r.stop = 0 380 | r.connect() 381 | } 382 | 383 | }) 384 | } 385 | 386 | func newTcpConn(network, addr string, conn net.Conn, msgtyp MsgType, handler IMsgHandler, parser IParserFactory, user interface{}) *tcpMsgQue { 387 | msgque := tcpMsgQue{ 388 | msgQue: msgQue{ 389 | id: atomic.AddUint32(&msgqueId, 1), 390 | cwrite: make(chan *Message, 64), 391 | msgTyp: msgtyp, 392 | handler: handler, 393 | timeout: DefMsgQueTimeout, 394 | connTyp: ConnTypeConn, 395 | gmsgId: gmsgId, 396 | parserFactory: parser, 397 | lastTick: Timestamp, 398 | user: user, 399 | }, 400 | conn: conn, 401 | network: network, 402 | address: addr, 403 | } 404 | if parser != nil { 405 | msgque.parser = parser.Get() 406 | } 407 | msgqueMapSync.Lock() 408 | msgqueMap[msgque.id] = &msgque 409 | msgqueMapSync.Unlock() 410 | LogDebug("new msgque id:%d connect to addr:%s:%s", msgque.id, network, addr) 411 | return &msgque 412 | } 413 | 414 | func newTcpAccept(conn net.Conn, msgtyp MsgType, handler IMsgHandler, parser IParserFactory) *tcpMsgQue { 415 | msgque := tcpMsgQue{ 416 | msgQue: msgQue{ 417 | id: atomic.AddUint32(&msgqueId, 1), 418 | cwrite: make(chan *Message, 64), 419 | msgTyp: msgtyp, 420 | handler: handler, 421 | timeout: DefMsgQueTimeout, 422 | connTyp: ConnTypeAccept, 423 | gmsgId: gmsgId, 424 | lastTick: Timestamp, 425 | parserFactory: parser, 426 | }, 427 | conn: conn, 428 | } 429 | if parser != nil { 430 | msgque.parser = parser.Get() 431 | } 432 | msgqueMapSync.Lock() 433 | msgqueMap[msgque.id] = &msgque 434 | msgqueMapSync.Unlock() 435 | LogInfo("new msgque id:%d from addr:%s", msgque.id, conn.RemoteAddr().String()) 436 | return &msgque 437 | } 438 | 439 | func newTcpListen(listener net.Listener, msgtyp MsgType, handler IMsgHandler, parser IParserFactory, addr string) *tcpMsgQue { 440 | msgque := tcpMsgQue{ 441 | msgQue: msgQue{ 442 | id: atomic.AddUint32(&msgqueId, 1), 443 | msgTyp: msgtyp, 444 | handler: handler, 445 | parserFactory: parser, 446 | connTyp: ConnTypeListen, 447 | }, 448 | listener: listener, 449 | } 450 | 451 | msgqueMapSync.Lock() 452 | msgqueMap[msgque.id] = &msgque 453 | msgqueMapSync.Unlock() 454 | LogInfo("new tcp listen id:%d addr:%s", msgque.id, addr) 455 | return &msgque 456 | } 457 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # antnet 2 | 有疑问欢迎加群:828958110 3 | ## 第一次使用 4 |   在介绍antnet之前,我们先使用一次,看看antnet如何构建一个echo服务器 5 | ``` 6 | package main 7 | 8 | import ( 9 | "antnet" 10 | ) 11 | 12 | func main() { 13 | antnet.StartServer("tcp://:6666", antnet.MsgTypeCmd, &antnet.EchoMsgHandler{}, nil) 14 | antnet.WaitForSystemExit() 15 | } 16 | ``` 17 | 通过上面的代码我们就实现了一个最简单的echo服务器。 18 | 现在打开命令行,执行telnet 127.0.0.1 6666,输入一个字符串,回车后你将收到原样的回复消息。     19 | 20 | ## 设计 21 | antnet尽可能把功能相关的代码组织到一块,让你能快速找到代码,比如parser打头的文件表示解析器相关,msgque打头的文件表示消息队列相关,同时antnet的代码都是经过深思熟虑的,比如TCP连接的关闭时机等等 22 | 相关的说明我会发布在知乎: 23 | [整体设计原则](https://zhuanlan.zhihu.com/p/43600745) 24 | [UDP设计](https://zhuanlan.zhihu.com/p/41572002) 25 | [TCP设计(1)](https://zhuanlan.zhihu.com/p/43055894) 26 | [日志设计](https://zhuanlan.zhihu.com/p/43775835) 27 | [数组Map](https://zhuanlan.zhihu.com/p/160824599) 28 | [一把锁用go实现Actor模型](https://zhuanlan.zhihu.com/p/181289775) 29 | [谈谈游戏项目中的同步技术](https://zhuanlan.zhihu.com/p/160792618) 30 | 31 | ## 为什么选择antnet 32 | antnet在很多方面和市面上常见的框架都很不一样,因为antnet想充分利用go的特性,而非用c++写go,拿antnet的全局消息举例: 33 | 全局消息的设计被问得很多,因为antnet的全局消息和市面上的框架都不一样(详见上面的TCP设计(1)),很多人觉得的全局消息应该是在一个goroutine中for循环遍历所有的消息队列发送就行,因为c++的框架就是这样的 34 | 这样做的结果是什么呢,一个goroutine负责发送全局消息,一旦调用send,会被挂起,直到系统通知send完成,再进行下一个send,只能利用一个核心,而且经常被挂起,性能能高吗? 35 | 反观antnet的设计,每个消息队列自己处理全局消息,也就是多个goroutine同时发送的,一个goroutine挂起,正好给其他goroutine调用send的机会,充分利用多核,能保证全局消息最快速度发送出去 36 | 很多go程序员来自于c++,也就导致了很多go框架再用c++的思维编写,我自己也是8年c++老程序员了,也写过c++的网络库,所以怎么利用go的特性,而非c++移植到go,才是我关心的问题。 37 | 另外就是一些基础问题,antnet的设计里面考虑了很多网络细节,很多所谓的网络库连连接关闭时机这些都没有考虑,因为作者对网络理解不深,事实上,我招聘主程的要求就是能手写整个TCP状态转移图,虽然这个要求执行时都会放水 38 | 这就是为什么antnet和市面上的很多所谓的网络框架不一样的原因,知道得越多,知道的越少,希望诸君发现antnet细节写法很怪时考虑一下这句话,望与诸君共勉 39 | 40 | ## 依赖项 41 | github.com/golang/protobuf 42 | github.com/vmihailenco/msgpack 43 | github.com/go-redis/redis v6版本 44 | github.com/gorilla/websocket 45 | 46 | ## 生产环境 47 | antnet已服务全球数千万玩家,部分商业游戏案例: 48 | 《街篮2》https://www.taptap.com/app/175459 49 | 《灌篮高手》https://www.taptap.com/app/154129 50 | 当然antnet作为最基础的框架并没有实现RUDP,因为游戏类型不同,我更倾向于为每个游戏定制RUDP,所以RUDP在更高一层的战斗服里面。 51 | 当你使用race参数进行竞争测试时会发现有些报警,因为我允许对单个变量的同时读写,只在我认为必要的地方加锁,比如很多stop变量。 52 | 这些变量的使用都是经过认真思考的,并不会真正引发竞争问题,变量的竞争主要在: 53 | 1.值写入和读取的先后顺序,相关代码都经过认真思考和测试,先后顺序并不影响逻辑。 54 | 2.值写入了一半,如果对32位的值在16位架构下面确实可能,但现在服务器基本都是64位架构的,亦不存在此问题。 55 | 56 | ## 微信小程序 57 | antnet也支持H5研发,且为全行业唯一手游级H5产品。 58 | 微信搜索《美食大战老鼠2》《街机三国3》或者微信扫码,即可体验 59 | ![](https://gitee.com/magiclvzs/pic/raw/master/jjsg.jpg) 60 | ![](https://gitee.com/magiclvzs/pic/raw/master/ms.jpg) 61 | 62 | 63 | ## 测试框架 64 | https://github.com/magiclvzs/wsserver 65 | wsserver是一个websocket的测试框架,用于展示如何使用antnet 66 | 只有不到60行逻辑代码,实现了基于websocket+protobuf的聊天系统 67 | antnet的正式框架为union,由于商业性原因,暂时无法开源 68 | 69 | ## 架构 70 | |---------------------------------------------------| 71 | | 应用层(用户逻辑) | 72 | |---------------------------------------------------| 73 | | 处理层(IMsgHandler) | 74 | |---------------------------------------------------| 75 | | 解析层(IMsgParser,IParser,IParserFactory) | 76 | |---------------------------------------------------| 77 | | 网络层(IMsgQue,Message) | 78 | |---------------------------------------------------| 79 | 80 | 81 | ## 消息头 82 | 对于一个网络服务器,我们首先需要定义的是消息头,antnet的消息头长度为12个字节,定义如下 83 | ``` 84 | type MessageHead struct { 85 | Len uint32 //数据长度 86 | Error uint16 //错误码 87 | Cmd uint8 //命令 88 | Act uint8 //动作 89 | Index uint16 //序号 90 | Flags uint16 //标记 91 | } 92 | ``` 93 | 错误码用于快速返回一个错误,往往服务器返回错误时是不需要跟任何数据的。 94 | 其中cmd和act标识了消息的用途,cmd一般按照大功能分类,比如建筑模块,士兵模块,而act则是这些模块下面的活动,比如升级,建造等。 95 | index用于标识唯一的一次请求,客户端应该自增方式增加index,服务器会原样返回,这样就让客户端可以唯一标识每次请求。 96 | cmd和act,index共同组成了一个消息的tag,服务器在返回时往往需要原样返回一个消息的tag。 97 | flags是一个消息的选项,比如消息是否压缩,是否加密等等。   98 | 99 | ## 消息 100 | ``` 101 | type Message struct { 102 | Head *MessageHead //消息头,可能为nil 103 | Data []byte //消息数据 104 | IMsgParser //解析器 105 | User interface{} //用户自定义数据 106 | } 107 | ``` 108 | 消息是对一次交互的抽象,每个消息都会用自己的解析器,有消息头部分(可能为nil),和数据部分。 109 | 110 | ### 广播与组播消息 111 | antnet对这类消息有特殊处理,并不是简单的for循环发送,性能可以得到保证。 112 | 使用Send函数可以方便的发送全局消息。 113 | 使用SendGroup可以发送组播消息,一个消息队列可以设置N个组id,比如针对房间号和公会分别设置。 114 | 115 | ## 消息队列 116 | antnet将数据流抽象为消息队列,无论是来自tcp,udp还是websocket的数据流,都会被抽象为消息队列。     117 | 根据是否带有消息头,antnet将消息队列分为两种类型:   118 | ``` 119 | type MsgType int 120 | 121 | const ( 122 | MsgTypeMsg MsgType = iota //消息基于确定的消息头 123 | MsgTypeCmd //消息没有消息头,以\n分割 124 | ) 125 | ``` 126 | 127 | ## 解析器 128 | antnet目前有六种解析器类型:   129 | ``` 130 | type ParserType int 131 | 132 | const ( 133 | ParserTypePB ParserType = iota //protobuf类型,用于和客户端交互 134 | ParserTypeCmd //cmd类型,类似telnet指令,用于直接和程序交互 135 | ParserTypeJson //json类型,可以用于客户端或者服务器之间交互 136 | ParserTypeMsgpack //msgpack类型,可以用于客户端或者服务器之间交互 137 | ParserTypeCustom //自定义类型 138 | ParserTypeRaw //不做任何解析 139 | ) 140 | ``` 141 | 这六种类型的解析器,都可以用antnet.Parser来创建。 142 | 每个解析器需要一个Type字段和一个ErrType字段定义,Type字段表示了消息解析器的类型,而ErrType字段则决定了消息解析失败之后默认的行为,ErrType目前有4中方式:     143 | ``` 144 | type ParserType int 145 | 146 | const ( 147 | ParseErrTypeSendRemind ParseErrType = iota //消息解析失败发送提醒消息 148 | ParseErrTypeContinue //消息解析失败则跳过本条消息 149 | ParseErrTypeAlways //消息解析失败依然处理 150 | ParseErrTypeClose //消息解析失败则关闭连接 151 | ) 152 | ``` 153 | 154 | 默认的解析器Type是pb类型的,而错误处理是一旦解析出错给客户端发送提示消息。 155 | 比如我们现在有一个需求是根据玩家id获取玩家等级,那么我们可以建立一个cmd类型的解析器,这样我们就能直接通过telnet连接到服务器进行查询了,使用如下代码 156 | 创建一个cmd类型的解析器。 157 | ``` 158 | pf := &antnet.Parser{Type: antnet.ParserTypeCmd} 159 | ``` 160 | 上面的代码就定义了一个基于cmd模式的解析器。     161 | 162 | 定义好解析之后,就需要注册解析器需要解析的消息,解析器支持两种模式: 163 | 1. 基于MsgTypeMsg的,根据cmd和act进行解析,使用Register进行注册。 164 | 2. 基于MsgTypeCmd的,这种消息往往没有消息头,使用RegisterMsg进行注册。   165 | 两种类型的注册函数定义如下: 166 | ``` 167 | Register(cmd uint8, act uint8, c2s interface{}, s2c interface{}) 168 | RegisterMsg(c2s interface{}, s2c interface{}) 169 | ``` 170 | #### 命令行解析器 171 | 命令行解析器用于解析命令行输入,类似telnet,我希望但服务器运行起来之后有一个非常简单的交流接口,直接基于telnet是最好了,而这个解析器就是为此准备,他可以接收不完整的输入,只要你最终输入完整即可,也可以接收你错误的输入,直到你输入正确为止。   172 | 命令行解析器目前支持两种tag: 173 | 1. `match:"k"`表示只需要匹配字段名即可,为了减少输入的大小写切换,在匹配的时候会将字段名默认作为小写匹配。 174 | 2. `match:"kv"`表示需要匹配字段名和字段值   175 | 命令行解析器的注册需要一个结构体,比如上面例子,需要查询玩家等级的,我们的定义如下: 176 | ``` 177 | type GetGamerLevel struct { 178 | Get string `match:"k"` 179 | Gamer int 180 | Level int `match:"k"` 181 | } 182 | ``` 183 | 三个字段解释如下: 184 | 1. Get字段,表示方法,比如get,set,reload,这种情况我只需要输入方法即可,而tag `match:"k"`则表示只需要匹配字段名即可   185 | 2. Gamer字段,表示玩家id,没有tag,对于没有tag的字段,解析器会认为需要匹配字段名和值,比如输入gamer 1 会被认为合法,而gamer test则不合法,因为test不是int 186 | 3. Level字段,表示玩家等级,有tag,表示只需要匹配level这个字段名即可。   187 | 定义好结构体之后我们需要注册到解析器,使用如下代码注册即可: 188 | ``` 189 | pf.RegisterMsg(&GetGamerLevel{}, nil) 190 | ``` 191 | 这样我们就把这个消息注册到了解析器 192 | #### protobuf解析器 193 | protobuf解析器用于解析pb类型的数据 194 | 195 | #### 自定义解析器 196 | 但上述的解析器无法满足要求时,可以自定义解析器,只需要实现IParserFactory即可 197 | 198 | ## 处理器 199 | 处理器用于处理消息,一个处理器应该实现IMsgHandler消息接口: 200 | ``` 201 | type IMsgHandler interface { 202 | OnNewMsgQue(msgque IMsgQue) bool //新的消息队列 203 | OnDelMsgQue(msgque IMsgQue) //消息队列关闭 204 | OnProcessMsg(msgque IMsgQue, msg *Message) bool //默认的消息处理函数 205 | OnConnectComplete(msgque IMsgQue, ok bool) bool //连接成功 206 | GetHandlerFunc(msgque IMsgQue, msg *Message) HandlerFunc //根据消息获得处理函数 207 | } 208 | ``` 209 | 210 | 当然,一般情况,我们并不需要完全实现上面的接口,你只需在你的处理器里面添加antnet.DefMsgHandler定义即可。 211 | 在antnet.DefMsgHandler里面,同样定义了Register和RegisterMsg函数,原理和解析器一样,也是为了区分不同的输入。 212 | 如果你没有注册任何消息处理函数,系统会自动调用OnProcessMsg函数,如果你有定义的话。     213 | 214 | 在上面根据玩家id获取玩家等级的例子中,我们这样定义处理器:   215 | ``` 216 | type Handler struct { 217 | antnet.DefMsgHandler 218 | } 219 | ``` 220 | 定义好处理器之后我们需要创建处理器以及注册要处理的消息以和理函数:     221 | ``` 222 | h := &Handler{} 223 | h.RegisterMsg(&GetGamerLevel{}, func(msgque antnet.IMsgQue, msg *antnet.Message) bool { 224 | c2s := msg.C2S().(*GetGamerLevel) 225 | c2s.Level = 8 226 | msgque.SendStringLn(msg.C2SString()) 227 | return true 228 | }) 229 | ``` 230 | 这样我们就创建了一个处理器以及注册处理函数 231 | 232 | #### 处理器的调用时机 233 | antnet会为每个tcp链接建立两个goroutine进行服务一个用于读,一个用于写,处理的回调发生在每个链接的读的goroutine之上,为什么要这么设计,是考虑当客户端的一个消息没有处理完成的时候真的有必要立即处理下一个消息吗? 234 | 235 | ## 启动服务 236 | 启动一个网络服务器使用antnet.StartServer函数,他被定义在msgque.go文件里面,一个服务目前需要一个处理器和一个解析器才可以运行。 237 | 在上面根据玩家id获取玩家等级的例子中,我们这样启动服务:   238 | ``` 239 | antnet.StartServer("tcp://:6666", antnet.MsgTypeCmd, h, pf) 240 | ``` 241 | 在服务启动后我们需要等待ctrl+C消息以结束服务,使用WaitForSystemExit()函数即可。     242 | 完整示例: 243 | ``` 244 | package main 245 | 246 | import "antnet" 247 | 248 | type GetGamerLevel struct { 249 | Get string `match:"k"` 250 | Gamer int 251 | Level int `match:"k"` 252 | } 253 | 254 | type Handler struct { 255 | antnet.DefMsgHandler 256 | } 257 | func test(msgque antnet.IMsgQue, msg *antnet.Message) bool { 258 | c2s := msg.C2S().(*GetGamerLevel) 259 | c2s.Level = 8 260 | msgque.SendStringLn(msg.C2SString()) 261 | return true 262 | } 263 | func main() { 264 | pf := &antnet.Parser{Type: antnet.ParserTypeCmd} 265 | pf.RegisterMsg(&GetGamerLevel{}, nil) 266 | 267 | h := &Handler{} 268 | h.RegisterMsg(&GetGamerLevel{}, test) 269 | 270 | antnet.StartServer("tcp://:6666", antnet.MsgTypeCmd, h, pf) 271 | antnet.WaitForSystemExit() 272 | } 273 | ``` 274 | 在这个示例中,我们建立了一个基于命令的网络应用。 275 | 现在打开命令行,执行telnet 127.0.0.1 6666。 276 | 输入字符串 get gamer 1 level,你将收到回复{"Get":"get","Gamer":1,"Level":8} 277 | 上面的例子模拟了一个游戏服务器常见的需求,即命令行式的交互,这对于游戏后台的调试以及某些gm指令的执行非常有效。   278 | 279 | 280 | 在上面的例子中如果你的解析器是基于json的,输入{"GetGamerLevel":{"Get":"get","Gamer":1,"Level":0}}也能得到回复。 281 | ## 全局变量 282 | 为了方便使用antnet封装了一些全局变量: 283 | 1. StartTick 用于标识antnet启动的时刻,是一个毫秒级的时间戳 284 | 2. NowTick 用于标识antnet现在的时刻,是一个自动变化的毫秒级时间戳 285 | 3. DefMsgQueTimeout 默认的网络超时,当超过这个时间和客户端没有交互,antnet将断开连接,默认是30s 286 | 4. MaxMsgDataSize 默认的最大数据长度,超过这个长度的消息将会被拒绝并关闭连接,默认为1MB 287 | 288 | ## 全局函数 289 | 为了方便使用antnet封装了一些全局函数以供调用: 290 | 1. WaitForSystemExit 用于等待用户输入ctrl+C以结束进程。 291 | 2. Go 用于创建可被antnet管理的goroutine 292 | 2. Go2 同Go,不同的是会有个默认的channel,以通知antnet的结束 293 | 3. Stop 结束antnet 294 | 4. Println 再也不想需要打印某些调试信息的时候导入fmt,而打印完成又去删除fmt引用了 295 | 5. Printf 同上 296 | 6. Sprintf 同上 297 | 7. IsStop antnet是否停止 298 | 8. IsRuning antnet是否运行中 299 | 9. PathExists 判断路径是否存在 300 | 10. Daemon 进入精灵进程 301 | 11. GetStatis 获得antnet的统计信息 302 | 12. Atoi 简化字符串到数值 303 | 13. Itoa 简化数值到字符串 304 | 14. ParseBaseKind 字符串到特定类型的转化 305 | 15. CmdAct 将cmd和act转为一个int   306 | 16. SetTimeout 设置一个定时器 307 | 17. DelTimeout 删除定时器 308 | 18. LogXXX 日志系列函数 309 | 310 | ## 日志 311 | antnet会默认会产生一个日志系统,通过antnet.Logxxx即可输出不同等级的日志。 312 | 日志等级分类如下: 313 | ``` 314 | const ( 315 | LogLevelAllOn LogLevel = iota //开放说有日志 316 | LogLevelDebug //调试信息 317 | LogLevelInfo //资讯讯息 318 | LogLevelWarn //警告状况发生 319 | LogLevelError //一般错误,可能导致功能不正常 320 | LogLevelFatal //严重错误,会导致进程退出 321 | LogLevelAllOff //关闭所有日志 322 | ) 323 | ``` 324 | 325 | ## redis封装 326 | antnet对redis进行了一下封装。 327 | antnet.Redis代表了对redis的一个封装,主要记录了对eval指令的处理,能购把预先生成的lua脚本上传到redis得到hash,以后使用evalsha命令进行调用。 328 | RedisManager用于管理一组redis数据库。   329 | 330 | ## 定时器 331 | antnet会默认运行一个基于时间轮的计时器,精度是毫秒,用于定时器使用。 332 | 333 | ## 数据模型 334 | antnet自带了一个基于redis的数据模型处理,使用protobuf作为数据库定义语言,默认情况下,redis内部存储的数据是msgpack格式的,处理的时候你可以非常方便的将他转换为protobuf数据流发给你的客户端。   335 | 你可以使用protobuf产生的go结构体作为数据模型,当存入redis时,存入msgpack字节流,之所以这么做,是为了方便redis里面能直接用lua脚本操作单个字段。   336 | 当从数据库读出后,你可以方便的将他转换为pb字节流,填充到你定义好的pb结构体中,发送给客户端。 337 | -------------------------------------------------------------------------------- /func.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "bytes" 5 | "crypto/md5" 6 | "encoding/gob" 7 | "encoding/hex" 8 | "errors" 9 | "math/rand" 10 | "os" 11 | "os/exec" 12 | "os/signal" 13 | "path/filepath" 14 | "reflect" 15 | "strconv" 16 | "strings" 17 | "sync/atomic" 18 | "syscall" 19 | "time" 20 | ) 21 | 22 | func AddStopCheck(cs string) uint64 { 23 | id := atomic.AddUint64(&stopCheckIndex, 1) 24 | if id == 0 { 25 | id = atomic.AddUint64(&stopCheckIndex, 1) 26 | } 27 | stopCheckMap.Lock() 28 | stopCheckMap.M[id] = cs 29 | stopCheckMap.Unlock() 30 | return id 31 | } 32 | 33 | func RemoveStopCheck(id uint64) { 34 | stopCheckMap.Lock() 35 | delete(stopCheckMap.M, id) 36 | stopCheckMap.Unlock() 37 | } 38 | 39 | func AtExit(fun func()) { 40 | id := atomic.AddUint32(&atexitId, 1) 41 | if id == 0 { 42 | id = atomic.AddUint32(&atexitId, 1) 43 | } 44 | 45 | atexitMapSync.Lock() 46 | atexitMap[id] = fun 47 | atexitMapSync.Unlock() 48 | } 49 | 50 | func stopServer() { 51 | if !atomic.CompareAndSwapInt32(&stop, 0, 1) { 52 | return 53 | } 54 | 55 | close(stopChanForGo) 56 | for sc := 0; !waitAll.TryWait(); sc++ { 57 | Sleep(1) 58 | if sc >= Config.StopTimeout { 59 | LogError("Server Stop Timeout") 60 | stopCheckMap.Lock() 61 | for _, v := range stopCheckMap.M { 62 | LogError("Server Stop Timeout:%v", v) 63 | } 64 | stopCheckMap.Unlock() 65 | break 66 | } 67 | } 68 | 69 | Try(func() { 70 | close(stopChanForSys) 71 | LogInfo("Server Stop From Ctrl+C") 72 | }, func(i interface{}) { 73 | LogInfo("Server Stop From Call Stop") 74 | }) 75 | } 76 | 77 | func Stop() { 78 | close(stopChanForSys) 79 | } 80 | 81 | func IsStop() bool { 82 | return stop == 1 83 | } 84 | 85 | func IsRuning() bool { 86 | return stop == 0 87 | } 88 | 89 | func CmdAct(cmd, act uint8) int { 90 | return int(cmd)<<8 + int(act) 91 | } 92 | 93 | func Tag(cmd, act uint8, index uint16) int { 94 | return int(cmd)<<16 + int(act)<<8 + int(index) 95 | } 96 | 97 | func MD5Str(s string) string { 98 | return MD5Bytes([]byte(s)) 99 | } 100 | 101 | func MD5Bytes(s []byte) string { 102 | md5Ctx := md5.New() 103 | md5Ctx.Write(s) 104 | cipherStr := md5Ctx.Sum(nil) 105 | return hex.EncodeToString(cipherStr) 106 | } 107 | 108 | func MD5File(path string) string { 109 | data, err := ReadFile(path) 110 | if err != nil { 111 | LogError("calc md5 failed path:%v", path) 112 | return "" 113 | } 114 | return MD5Bytes(data) 115 | } 116 | 117 | func WaitForSystemExit(atexit ...func()) { 118 | statis.StartTime = time.Now() 119 | signal.Notify(stopChanForSys, os.Interrupt, os.Kill, syscall.SIGTERM) 120 | select { 121 | case <-stopChanForSys: 122 | stopServer() 123 | } 124 | for _, v := range atexit { 125 | if v != nil { 126 | v() 127 | } 128 | } 129 | atexitMapSync.Lock() 130 | for _, v := range atexitMap { 131 | v() 132 | } 133 | atexitMapSync.Unlock() 134 | for _, v := range redisManagers { 135 | v.close() 136 | } 137 | waitAllForRedis.Wait() 138 | if !atomic.CompareAndSwapInt32(&stopForLog, 0, 1) { 139 | return 140 | } 141 | close(stopChanForLog) 142 | waitAllForLog.Wait() 143 | } 144 | 145 | func Daemon(skip ...string) { 146 | if os.Getppid() != 1 { 147 | filePath, _ := filepath.Abs(os.Args[0]) 148 | newCmd := []string{os.Args[0]} 149 | add := 0 150 | for _, v := range os.Args[1:] { 151 | if add == 1 { 152 | add = 0 153 | continue 154 | } else { 155 | add = 0 156 | } 157 | for _, s := range skip { 158 | if strings.Contains(v, s) { 159 | if strings.Contains(v, "--") { 160 | add = 2 161 | } else { 162 | add = 1 163 | } 164 | break 165 | } 166 | } 167 | if add == 0 { 168 | newCmd = append(newCmd, v) 169 | } 170 | } 171 | Println("go daemon args:", newCmd) 172 | cmd := exec.Command(filePath) 173 | cmd.Args = newCmd 174 | cmd.Start() 175 | } 176 | } 177 | 178 | func GetStatis() *Statis { 179 | statis.GoCount = int(gocount) 180 | statis.MsgqueCount = len(msgqueMap) 181 | statis.PoolGoCount = poolGoCount 182 | return statis 183 | } 184 | 185 | func Atoi(str string) int { 186 | i, err := strconv.Atoi(str) 187 | if err != nil { 188 | return 0 189 | } 190 | return i 191 | } 192 | 193 | func Atoi64(str string) int64 { 194 | i, err := strconv.ParseInt(str, 10, 64) 195 | if err != nil { 196 | LogError("str to int64 failed err:%v", err) 197 | return 0 198 | } 199 | return i 200 | } 201 | 202 | func Atof(str string) float32 { 203 | i, err := strconv.ParseFloat(str, 32) 204 | if err != nil { 205 | LogError("str to int64 failed err:%v", err) 206 | return 0 207 | } 208 | return float32(i) 209 | } 210 | 211 | func Atof64(str string) float64 { 212 | i, err := strconv.ParseFloat(str, 64) 213 | if err != nil { 214 | LogError("str to int64 failed err:%v", err) 215 | return 0 216 | } 217 | return i 218 | } 219 | 220 | func Itoa(num interface{}) string { 221 | switch n := num.(type) { 222 | case int8: 223 | return strconv.FormatInt(int64(n), 10) 224 | case int16: 225 | return strconv.FormatInt(int64(n), 10) 226 | case int32: 227 | return strconv.FormatInt(int64(n), 10) 228 | case int: 229 | return strconv.FormatInt(int64(n), 10) 230 | case int64: 231 | return strconv.FormatInt(int64(n), 10) 232 | case uint8: 233 | return strconv.FormatUint(uint64(n), 10) 234 | case uint16: 235 | return strconv.FormatUint(uint64(n), 10) 236 | case uint32: 237 | return strconv.FormatUint(uint64(n), 10) 238 | case uint: 239 | return strconv.FormatUint(uint64(n), 10) 240 | case uint64: 241 | return strconv.FormatUint(uint64(n), 10) 242 | } 243 | return "" 244 | } 245 | 246 | func Try(fun func(), handler func(interface{})) { 247 | defer func() { 248 | if err := recover(); err != nil { 249 | if handler == nil { 250 | LogStack() 251 | LogError("error catch:%v", err) 252 | } else { 253 | handler(err) 254 | } 255 | atomic.AddInt32(&statis.PanicCount, 1) 256 | statis.LastPanic = int(Timestamp) 257 | } 258 | }() 259 | fun() 260 | } 261 | 262 | func Try2(fun func(), handler func(interface{})) { 263 | defer func() { 264 | if err := recover(); err != nil { 265 | LogStack() 266 | LogError("error catch:%v", err) 267 | if handler != nil { 268 | handler(err) 269 | } 270 | atomic.AddInt32(&statis.PanicCount, 1) 271 | statis.LastPanic = int(Timestamp) 272 | } 273 | }() 274 | fun() 275 | } 276 | 277 | func ParseBaseKind(kind reflect.Kind, data string) (interface{}, error) { 278 | switch kind { 279 | case reflect.String: 280 | return data, nil 281 | case reflect.Bool: 282 | v := data == "1" || data == "true" 283 | return v, nil 284 | case reflect.Int: 285 | x, err := strconv.ParseInt(data, 0, 64) 286 | return int(x), err 287 | case reflect.Int8: 288 | x, err := strconv.ParseInt(data, 0, 8) 289 | return int8(x), err 290 | case reflect.Int16: 291 | x, err := strconv.ParseInt(data, 0, 16) 292 | return int16(x), err 293 | case reflect.Int32: 294 | x, err := strconv.ParseInt(data, 0, 32) 295 | return int32(x), err 296 | case reflect.Int64: 297 | x, err := strconv.ParseInt(data, 0, 64) 298 | return int64(x), err 299 | case reflect.Float32: 300 | x, err := strconv.ParseFloat(data, 32) 301 | return float32(x), err 302 | case reflect.Float64: 303 | x, err := strconv.ParseFloat(data, 64) 304 | return float64(x), err 305 | case reflect.Uint: 306 | x, err := strconv.ParseUint(data, 10, 64) 307 | return uint(x), err 308 | case reflect.Uint8: 309 | x, err := strconv.ParseUint(data, 10, 8) 310 | return uint8(x), err 311 | case reflect.Uint16: 312 | x, err := strconv.ParseUint(data, 10, 16) 313 | return uint16(x), err 314 | case reflect.Uint32: 315 | x, err := strconv.ParseUint(data, 10, 32) 316 | return uint32(x), err 317 | case reflect.Uint64: 318 | x, err := strconv.ParseUint(data, 10, 64) 319 | return uint64(x), err 320 | default: 321 | LogError("parse failed type not found type:%v data:%v", kind, data) 322 | return nil, errors.New("type not found") 323 | } 324 | } 325 | 326 | func GobPack(e interface{}) ([]byte, error) { 327 | var bio bytes.Buffer 328 | enc := gob.NewEncoder(&bio) 329 | err := enc.Encode(e) 330 | if err != nil { 331 | return nil, ErrGobPack 332 | } 333 | return bio.Bytes(), nil 334 | } 335 | 336 | func GobUnPack(data []byte, msg interface{}) error { 337 | bio := bytes.NewBuffer(data) 338 | enc := gob.NewDecoder(bio) 339 | err := enc.Decode(msg) 340 | if err != nil { 341 | return ErrGobUnPack 342 | } 343 | return nil 344 | } 345 | 346 | func ParseBool(s string) bool { 347 | if s == "1" || s == "true" { 348 | return true 349 | } 350 | return false 351 | } 352 | 353 | func ParseUint32(s string) uint32 { 354 | value, err := strconv.ParseUint(s, 10, 32) 355 | if err != nil { 356 | return 0 357 | } 358 | return uint32(value) 359 | } 360 | func ParseUint64(s string) uint64 { 361 | value, err := strconv.ParseUint(s, 10, 64) 362 | if err != nil { 363 | return 0 364 | } 365 | return uint64(value) 366 | } 367 | 368 | func ParseInt32(s string) int32 { 369 | value, err := strconv.ParseInt(s, 10, 32) 370 | if err != nil { 371 | return 0 372 | } 373 | return int32(value) 374 | } 375 | func ParseInt64(s string) int64 { 376 | value, err := strconv.ParseInt(s, 10, 64) 377 | if err != nil { 378 | return 0 379 | } 380 | return int64(value) 381 | } 382 | 383 | // 固定形式 x&y&z 384 | func Split1(s string, retSlice *[]uint32) { 385 | slice := strings.Split(s, "&") 386 | *retSlice = make([]uint32, 0, len(slice)) 387 | for _, value := range slice { 388 | *retSlice = append(*retSlice, ParseUint32(value)) 389 | } 390 | } 391 | 392 | // 固定形式 x&y&z;a&b&c;l_m_n 393 | func Split2(s string, retSlice *[][]uint32) { 394 | slice1 := strings.Split(s, ";") 395 | *retSlice = make([][]uint32, 0, len(slice1)) 396 | for _, value := range slice1 { 397 | var sl1 []uint32 398 | Split1(value, &sl1) 399 | *retSlice = append(*retSlice, sl1) 400 | } 401 | } 402 | 403 | // 固定形式 x&y&z;a&b&c:x&y&z;a&b&c 404 | func Split3(s string, retSlice *[][][]uint32) { 405 | slice1 := strings.Split(s, ":") 406 | *retSlice = make([][][]uint32, 0, len(slice1)) 407 | for _, value := range slice1 { 408 | var sl2 [][]uint32 409 | Split2(value, &sl2) 410 | *retSlice = append(*retSlice, sl2) 411 | } 412 | } 413 | 414 | // 固定形式 x&y&z 415 | func SplitString1(s string, retSlice *[]string) { 416 | *retSlice = strings.Split(s, "&") 417 | } 418 | 419 | // 固定形式 x&y&z;a&b&c;l_m_n 420 | func SplitString2(s string, retSlice *[][]string) { 421 | slice1 := strings.Split(s, ";") 422 | *retSlice = make([][]string, 0, len(slice1)) 423 | for _, value := range slice1 { 424 | *retSlice = append(*retSlice, strings.Split(value, "&")) 425 | } 426 | } 427 | 428 | // 固定形式 x&y&z;a&b&c:x&y&z;a&b&c: 429 | func SplitString3(s string, retSlice *[][][]string) { 430 | slice1 := strings.Split(s, ":") 431 | *retSlice = make([][][]string, 0, len(slice1)) 432 | for _, value := range slice1 { 433 | var sl2 [][]string 434 | SplitString2(value, &sl2) 435 | *retSlice = append(*retSlice, sl2) 436 | } 437 | } 438 | 439 | // 随机数返回[min,max) 440 | func RandBetween(min, max int) int { 441 | if min >= max || max == 0 { 442 | return max 443 | } 444 | 445 | randIndex++ 446 | r := rand.New(rand.NewSource(int64(randIndex) + Timestamp)) 447 | random := r.Intn(max-min) + min 448 | return random 449 | } 450 | 451 | func RandString(count int) string { 452 | var randomstr string 453 | for r := 0; r < count; r++ { 454 | i := RandBetween(65, 90) 455 | a := rune(i) 456 | randomstr += string(a) 457 | } 458 | return randomstr 459 | } 460 | 461 | // 随机数返回[min,max)中的count个不重复数值 462 | // 一般用来从数组中随机一部分数据的下标 463 | // 2个随机数种子保证参数相同,返回值不一定相同,达到伪随机目的 464 | func RandSliceBetween(min, max, count int) []int { 465 | if min > max { 466 | min, max = max, min 467 | } 468 | if min == max || max == 0 || count <= 0 { 469 | return []int{max} 470 | } 471 | randomRange := max - min 472 | retSlice := make([]int, 0, count) 473 | if count >= randomRange { 474 | for i := min; i < max; i++ { 475 | retSlice = append(retSlice, i) 476 | } 477 | return retSlice 478 | } 479 | randIndex++ 480 | r := rand.New(rand.NewSource(int64(randIndex) + Timestamp)) 481 | random := r.Intn(randomRange) + min 482 | baseRand := RandBetween(random*min, random*max) 483 | retSlice = append(retSlice, random) 484 | for i := 1; i < count; i++ { 485 | random = (i+baseRand*random)%randomRange + min 486 | isReapeated := false 487 | for j := 0; j < count; j++ { 488 | for _, v := range retSlice { 489 | if random == v { 490 | isReapeated = true 491 | break 492 | } 493 | } 494 | if isReapeated { 495 | random = (random-min+1)%randomRange + min 496 | } else { 497 | break 498 | } 499 | } 500 | retSlice = append(retSlice, random) 501 | } 502 | 503 | return retSlice 504 | } 505 | 506 | type valueWeightItem struct { 507 | weight uint32 508 | value uint64 509 | } 510 | 511 | // 权值对,根据权重随机一个值出来 512 | type GBValueWeightPair struct { 513 | allweight uint32 514 | valuelist []*valueWeightItem 515 | } 516 | 517 | func NewValueWeightPair() *GBValueWeightPair { 518 | return &GBValueWeightPair{} 519 | } 520 | 521 | func (this *GBValueWeightPair) Add(weight uint32, value uint64) { 522 | if weight == 0 { 523 | return 524 | } 525 | valueinfo := &valueWeightItem{weight, value} 526 | this.valuelist = append(this.valuelist, valueinfo) 527 | this.allweight += weight 528 | } 529 | 530 | func (this *GBValueWeightPair) Random() uint64 { 531 | if 1 == len(this.valuelist) { 532 | return this.valuelist[0].value 533 | } 534 | if this.allweight > 0 { 535 | randvalue := uint32(rand.Intn(int(this.allweight))) + 1 //[1,allweight] 536 | addweight := uint32(0) 537 | for i := 0; i < len(this.valuelist); i++ { 538 | addweight += this.valuelist[i].weight 539 | if randvalue <= addweight { 540 | return this.valuelist[i].value 541 | } 542 | } 543 | } 544 | return 0 545 | } 546 | func (this *GBValueWeightPair) GetValueList() []*valueWeightItem { 547 | return this.valuelist 548 | } 549 | func SafeSubInt32(a, b int32) int32 { 550 | if a > b { 551 | return a - b 552 | } 553 | return 0 554 | } 555 | 556 | func SafeSub(a, b uint32) uint32 { 557 | if a > b { 558 | return a - b 559 | } 560 | return 0 561 | } 562 | func SafeSub64(a, b uint64) uint64 { 563 | if a > b { 564 | return a - b 565 | } 566 | return 0 567 | } 568 | 569 | func SafeSubInt64(a, b int64) int64 { 570 | if a > b { 571 | return a - b 572 | } 573 | return 0 574 | } 575 | 576 | // 三元运算符 577 | func Ternary(val1 bool, ret1, ret2 interface{}) interface{} { 578 | if val1 { 579 | return ret1 580 | } 581 | return ret2 582 | } 583 | -------------------------------------------------------------------------------- /msgque.go: -------------------------------------------------------------------------------- 1 | package antnet 2 | 3 | import ( 4 | "net" 5 | "reflect" 6 | "strings" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | var DefMsgQueTimeout int = 180 12 | 13 | type MsgType int 14 | 15 | const ( 16 | MsgTypeMsg MsgType = iota //消息基于确定的消息头 17 | MsgTypeCmd //消息没有消息头,以\n分割 18 | ) 19 | 20 | type NetType int 21 | 22 | const ( 23 | NetTypeTcp NetType = iota //TCP类型 24 | NetTypeUdp //UDP类型 25 | NetTypeWs //websocket 26 | ) 27 | 28 | type ConnType int 29 | 30 | const ( 31 | ConnTypeListen ConnType = iota //监听 32 | ConnTypeConn //连接产生的 33 | ConnTypeAccept //Accept产生的 34 | ) 35 | 36 | type IMsgQue interface { 37 | Id() uint32 38 | GetMsgType() MsgType 39 | GetConnType() ConnType 40 | GetNetType() NetType 41 | 42 | LocalAddr() string 43 | RemoteAddr() string 44 | SetRealRemoteAddr(addr string) 45 | 46 | Stop() 47 | IsStop() bool 48 | Available() bool 49 | IsProxy() bool 50 | 51 | Send(m *Message) (re bool) 52 | SendString(str string) (re bool) 53 | SendStringLn(str string) (re bool) 54 | SendByteStr(str []byte) (re bool) 55 | SendByteStrLn(str []byte) (re bool) 56 | SendCallback(m *Message, c chan *Message) (re bool) 57 | DelCallback(m *Message) 58 | SetTimeout(t int) 59 | SetCmdReadRaw() 60 | GetTimeout() int 61 | Reconnect(t int) //重连间隔 最小1s,此函数仅能连接关闭是调用 62 | SetDiscardMsg(discard bool) 63 | 64 | GetHandler() IMsgHandler 65 | 66 | SetUser(user interface{}) 67 | GetUser() interface{} 68 | 69 | SetGroupId(group string) 70 | DelGroupId(group string) 71 | ClearGroupId() 72 | IsInGroup(group string) bool 73 | //服务器内部通讯时提升效率,比如战斗服发送消息到网关服,应该在连接建立时使用,cwriteCnt大于0表示重新设置cwrite缓存长度,内网一般发送较快,不用考虑 74 | SetMultiplex(multiplex bool, cwriteCnt int) bool 75 | 76 | tryCallback(msg *Message) (re bool) 77 | } 78 | 79 | type msgQue struct { 80 | id uint32 //唯一标示 81 | 82 | cwrite chan *Message //写入通道 83 | stop int32 //停止标记 84 | msgTyp MsgType //消息类型 85 | connTyp ConnType //通道类型 86 | 87 | handler IMsgHandler //处理者 88 | parser IParser 89 | parserFactory IParserFactory 90 | timeout int //传输超时 91 | lastTick int64 92 | 93 | init bool 94 | available bool 95 | multiplex bool 96 | callback map[int]chan *Message 97 | group map[string]int 98 | user interface{} 99 | callbackLock sync.Mutex 100 | gmsgId uint16 101 | discard bool 102 | realRemoteAddr string //当使用代理是,需要特殊设置客户端真实IP 103 | } 104 | 105 | func (r *msgQue) SetUser(user interface{}) { 106 | r.user = user 107 | } 108 | 109 | func (r *msgQue) getGMsg(add bool) *gMsg { 110 | if add { 111 | r.gmsgId++ 112 | } 113 | gm := gmsgArray[r.gmsgId] 114 | return gm 115 | } 116 | func (r *msgQue) SetCmdReadRaw() { 117 | 118 | } 119 | func (r *msgQue) Available() bool { 120 | return r.available 121 | } 122 | 123 | func (r *msgQue) GetUser() interface{} { 124 | return r.user 125 | } 126 | 127 | func (r *msgQue) GetHandler() IMsgHandler { 128 | return r.handler 129 | } 130 | 131 | func (r *msgQue) GetMsgType() MsgType { 132 | return r.msgTyp 133 | } 134 | 135 | func (r *msgQue) GetConnType() ConnType { 136 | return r.connTyp 137 | } 138 | 139 | func (r *msgQue) Id() uint32 { 140 | return r.id 141 | } 142 | 143 | func (r *msgQue) SetTimeout(t int) { 144 | if t >= 0 { 145 | r.timeout = t 146 | } 147 | } 148 | 149 | func (r *msgQue) isTimeout(tick *time.Timer) bool { 150 | left := int(Timestamp - r.lastTick) 151 | if left < r.timeout || r.timeout == 0 { 152 | if r.timeout == 0 { 153 | tick.Reset(time.Second * time.Duration(DefMsgQueTimeout)) 154 | } else { 155 | tick.Reset(time.Second * time.Duration(r.timeout-left)) 156 | } 157 | return false 158 | } 159 | LogInfo("msgque close because timeout id:%v wait:%v timeout:%v", r.id, left, r.timeout) 160 | return true 161 | } 162 | 163 | func (r *msgQue) GetTimeout() int { 164 | return r.timeout 165 | } 166 | 167 | func (r *msgQue) Reconnect(t int) { 168 | 169 | } 170 | 171 | func (r *msgQue) IsProxy() bool { 172 | return r.realRemoteAddr != "" 173 | } 174 | 175 | func (r *msgQue) SetRealRemoteAddr(addr string) { 176 | r.realRemoteAddr = addr 177 | } 178 | 179 | func (r *msgQue) SetGroupId(group string) { 180 | r.callbackLock.Lock() 181 | if r.group == nil { 182 | r.group = make(map[string]int) 183 | } 184 | r.group[group] = 0 185 | r.callbackLock.Unlock() 186 | } 187 | 188 | func (r *msgQue) DelGroupId(group string) { 189 | r.callbackLock.Lock() 190 | if r.group != nil { 191 | delete(r.group, group) 192 | } 193 | r.callbackLock.Unlock() 194 | } 195 | 196 | func (r *msgQue) ClearGroupId() { 197 | r.callbackLock.Lock() 198 | r.group = nil 199 | r.callbackLock.Unlock() 200 | } 201 | 202 | func (r *msgQue) IsInGroup(group string) bool { 203 | re := false 204 | r.callbackLock.Lock() 205 | if r.group != nil { 206 | _, re = r.group[group] 207 | } 208 | r.callbackLock.Unlock() 209 | return re 210 | } 211 | 212 | func (r *msgQue) SetMultiplex(multiplex bool, cwriteCnt int) bool { 213 | t := r.multiplex 214 | r.multiplex = multiplex 215 | if cwriteCnt > 0 { 216 | r.cwrite = make(chan *Message, cwriteCnt) 217 | } 218 | return t 219 | } 220 | func (r *msgQue) SetDiscardMsg(discard bool) { 221 | r.discard = discard 222 | } 223 | func (r *msgQue) Send(m *Message) (re bool) { 224 | if r.discard { 225 | LogWarn("msgque discard msg by setting msgque:%v", r.id) 226 | return true 227 | } 228 | if m == nil || r.stop == 1 { 229 | return 230 | } 231 | defer func() { 232 | if err := recover(); err != nil { 233 | re = false 234 | } 235 | }() 236 | if Config.AutoCompressLen > 0 && m.Head != nil && m.Head.Len >= Config.AutoCompressLen && (m.Head.Flags&FlagCompress) == 0 { 237 | m.Head.Flags |= FlagCompress 238 | m.Data = GZipCompress(m.Data) 239 | m.Head.Len = uint32(len(m.Data)) 240 | } 241 | select { 242 | case r.cwrite <- m: 243 | default: 244 | canDiscard := false 245 | if m.Head != nil && m.Head.Flags&FlagCanDiscard > 0 { 246 | canDiscard = true 247 | } 248 | LogWarn("msgque write channel full msgque:%v canDiscard:%v", r.id, canDiscard) 249 | if canDiscard { 250 | return false 251 | } 252 | r.cwrite <- m 253 | } 254 | 255 | return true 256 | } 257 | 258 | func (r *msgQue) SendCallback(m *Message, c chan *Message) (re bool) { 259 | if c == nil || cap(c) < 1 { 260 | LogError("try send callback but chan is null or no buffer") 261 | return 262 | } 263 | if r.Send(m) { 264 | r.setCallback(m.Tag(), c) 265 | } else { 266 | c <- nil 267 | return 268 | } 269 | return true 270 | } 271 | 272 | func (r *msgQue) DelCallback(m *Message) { 273 | if r.callback == nil { 274 | return 275 | } 276 | r.callbackLock.Lock() 277 | delete(r.callback, m.Tag()) 278 | r.callbackLock.Unlock() 279 | } 280 | 281 | func (r *msgQue) SendString(str string) (re bool) { 282 | return r.Send(&Message{Data: []byte(str)}) 283 | } 284 | 285 | func (r *msgQue) SendStringLn(str string) (re bool) { 286 | return r.SendString(str + "\n") 287 | } 288 | 289 | func (r *msgQue) SendByteStr(str []byte) (re bool) { 290 | return r.SendString(string(str)) 291 | } 292 | 293 | func (r *msgQue) SendByteStrLn(str []byte) (re bool) { 294 | return r.SendString(string(str) + "\n") 295 | } 296 | 297 | func (r *msgQue) tryCallback(msg *Message) (re bool) { 298 | if r.callback == nil { 299 | return false 300 | } 301 | defer func() { 302 | if err := recover(); err != nil { 303 | 304 | } 305 | r.callbackLock.Unlock() 306 | }() 307 | r.callbackLock.Lock() 308 | if r.callback != nil { 309 | tag := msg.Tag() 310 | if c, ok := r.callback[tag]; ok { 311 | delete(r.callback, tag) 312 | c <- msg 313 | re = true 314 | } 315 | } 316 | return 317 | } 318 | 319 | func (r *msgQue) setCallback(tag int, c chan *Message) { 320 | defer func() { 321 | if err := recover(); err != nil { 322 | 323 | } 324 | r.callback[tag] = c 325 | r.callbackLock.Unlock() 326 | }() 327 | 328 | r.callbackLock.Lock() 329 | if r.callback == nil { 330 | r.callback = make(map[int]chan *Message) 331 | } 332 | oc, ok := r.callback[tag] 333 | if ok { //可能已经关闭 334 | oc <- nil 335 | } 336 | } 337 | 338 | func (r *msgQue) baseStop() { 339 | if r.cwrite != nil { 340 | close(r.cwrite) 341 | } 342 | 343 | for k, v := range r.callback { 344 | Try(func() { 345 | v <- nil 346 | }, func(i interface{}) { 347 | 348 | }) 349 | delete(r.callback, k) 350 | } 351 | msgqueMapSync.Lock() 352 | delete(msgqueMap, r.id) 353 | msgqueMapSync.Unlock() 354 | LogInfo("msgque close id:%d", r.id) 355 | } 356 | func (r *msgQue) processMsg(msgque IMsgQue, msg *Message) (re bool) { 357 | re = true 358 | if r.multiplex { 359 | Go(func() { 360 | r.processMsgTrue(msgque, msg) 361 | }) 362 | } else { 363 | Try(func() { 364 | re = r.processMsgTrue(msgque, msg) 365 | }, nil) 366 | } 367 | return re 368 | } 369 | func (r *msgQue) processMsgTrue(msgque IMsgQue, msg *Message) bool { 370 | if msg.Head != nil && msg.Head.Flags&FlagCompress > 0 && msg.Data != nil { 371 | data, err := GZipUnCompress(msg.Data) 372 | if err != nil { 373 | LogError("msgque uncompress failed msgque:%v cmd:%v act:%v len:%v err:%v", msgque.Id(), msg.Head.Cmd, msg.Head.Act, msg.Head.Len, err) 374 | return false 375 | } 376 | msg.Data = data 377 | msg.Head.Flags -= FlagCompress 378 | msg.Head.Len = uint32(len(msg.Data)) 379 | } 380 | if r.parser != nil { 381 | mp, err := r.parser.ParseC2S(msg) 382 | if err == nil { 383 | msg.IMsgParser = mp 384 | } else { 385 | if r.parser.GetErrType() == ParseErrTypeSendRemind { 386 | if msg.Head != nil { 387 | r.Send(r.parser.GetRemindMsg(err, r.msgTyp).CopyTag(msg)) 388 | } else { 389 | r.Send(r.parser.GetRemindMsg(err, r.msgTyp)) 390 | } 391 | return true 392 | } else if r.parser.GetErrType() == ParseErrTypeClose { 393 | return false 394 | } else if r.parser.GetErrType() == ParseErrTypeContinue { 395 | return true 396 | } 397 | } 398 | } 399 | if msgque.tryCallback(msg) { 400 | return true 401 | } 402 | f := r.handler.GetHandlerFunc(msgque, msg) 403 | if f == nil { 404 | f = r.handler.OnProcessMsg 405 | } 406 | return f(msgque, msg) 407 | } 408 | 409 | type HandlerFunc func(msgque IMsgQue, msg *Message) bool 410 | 411 | type IMsgHandler interface { 412 | OnNewMsgQue(msgque IMsgQue) bool //新的消息队列 413 | OnDelMsgQue(msgque IMsgQue) //消息队列关闭 414 | OnProcessMsg(msgque IMsgQue, msg *Message) bool //默认的消息处理函数 415 | OnConnectComplete(msgque IMsgQue, ok bool) bool //连接成功 416 | GetHandlerFunc(msgque IMsgQue, msg *Message) HandlerFunc //根据消息获得处理函数 417 | } 418 | 419 | type DefMsgHandler struct { 420 | msgMap map[int]HandlerFunc 421 | typeMap map[reflect.Type]HandlerFunc 422 | } 423 | 424 | func (r *DefMsgHandler) OnNewMsgQue(msgque IMsgQue) bool { return true } 425 | func (r *DefMsgHandler) OnDelMsgQue(msgque IMsgQue) {} 426 | func (r *DefMsgHandler) OnProcessMsg(msgque IMsgQue, msg *Message) bool { return true } 427 | func (r *DefMsgHandler) OnConnectComplete(msgque IMsgQue, ok bool) bool { return true } 428 | func (r *DefMsgHandler) GetHandlerFunc(msgque IMsgQue, msg *Message) HandlerFunc { 429 | if msg.Head == nil { 430 | if r.typeMap != nil { 431 | if f, ok := r.typeMap[reflect.TypeOf(msg.C2S())]; ok { 432 | return f 433 | } 434 | } 435 | } else if r.msgMap != nil { 436 | if f, ok := r.msgMap[msg.CmdAct()]; ok { 437 | return f 438 | } 439 | } 440 | 441 | return nil 442 | } 443 | 444 | func (r *DefMsgHandler) RegisterMsg(v interface{}, fun HandlerFunc) { 445 | msgType := reflect.TypeOf(v) 446 | if msgType == nil || msgType.Kind() != reflect.Ptr { 447 | LogFatal("message pointer required") 448 | return 449 | } 450 | if r.typeMap == nil { 451 | r.typeMap = map[reflect.Type]HandlerFunc{} 452 | } 453 | r.typeMap[msgType] = fun 454 | } 455 | 456 | func (r *DefMsgHandler) Register(cmd, act uint8, fun HandlerFunc) { 457 | if r.msgMap == nil { 458 | r.msgMap = map[int]HandlerFunc{} 459 | } 460 | r.msgMap[CmdAct(cmd, act)] = fun 461 | } 462 | 463 | type EchoMsgHandler struct { 464 | DefMsgHandler 465 | } 466 | 467 | func (r *EchoMsgHandler) OnProcessMsg(msgque IMsgQue, msg *Message) bool { 468 | msgque.Send(msg) 469 | return true 470 | } 471 | 472 | func StartServer(addr string, typ MsgType, handler IMsgHandler, parser IParserFactory) error { 473 | addrs := strings.Split(addr, "://") 474 | if addrs[0] == "tcp" || addrs[0] == "all" { 475 | listen, err := net.Listen("tcp", addrs[1]) 476 | if err == nil { 477 | msgque := newTcpListen(listen, typ, handler, parser, addr) 478 | Go(func() { 479 | LogDebug("process listen for tcp msgque:%d", msgque.id) 480 | msgque.listen() 481 | LogDebug("process listen end for tcp msgque:%d", msgque.id) 482 | }) 483 | } else { 484 | LogError("listen on %s failed, errstr:%s", addr, err) 485 | return err 486 | } 487 | } 488 | if addrs[0] == "udp" || addrs[0] == "all" { 489 | naddr, err := net.ResolveUDPAddr("udp", addrs[1]) 490 | if err != nil { 491 | LogError("listen on %s failed, errstr:%s", addr, err) 492 | return err 493 | } 494 | conn, err := net.ListenUDP("udp", naddr) 495 | if err == nil { 496 | msgque := newUdpListen(conn, typ, handler, parser, addr) 497 | Go(func() { 498 | LogDebug("process listen for udp msgque:%d", msgque.id) 499 | msgque.listen() 500 | LogDebug("process listen end for udp msgque:%d", msgque.id) 501 | }) 502 | } else { 503 | LogError("listen on %s failed, errstr:%s", addr, err) 504 | return err 505 | } 506 | } 507 | if addrs[0] == "ws" || addrs[0] == "wss" { 508 | naddr := strings.SplitN(addrs[1], "/", 2) 509 | url := "/" 510 | if len(naddr) > 1 { 511 | url = "/" + naddr[1] 512 | } 513 | if addrs[0] == "wss" { 514 | Config.EnableWss = true 515 | } 516 | if typ != MsgTypeCmd { 517 | LogInfo("ws type msgque noly support MsgTypeCmd now auto set to MsgTypeCmd") 518 | } 519 | msgque := newWsListen(naddr[0], url, MsgTypeCmd, handler, parser) 520 | Go(func() { 521 | LogDebug("process listen for ws msgque:%d", msgque.id) 522 | msgque.listen() 523 | LogDebug("process listen end for ws msgque:%d", msgque.id) 524 | }) 525 | } 526 | return nil 527 | } 528 | 529 | func StartConnect(netType string, addr string, typ MsgType, handler IMsgHandler, parser IParserFactory, user interface{}) IMsgQue { 530 | var msgque IMsgQue 531 | if netType == "ws" || netType == "wss" { 532 | msgque = newWsConn(addr, nil, typ, handler, parser, user) 533 | } else { 534 | msgque = newTcpConn(netType, addr, nil, typ, handler, parser, user) 535 | } 536 | if handler.OnNewMsgQue(msgque) { 537 | msgque.Reconnect(0) 538 | return msgque 539 | } else { 540 | msgque.Stop() 541 | } 542 | return nil 543 | } 544 | --------------------------------------------------------------------------------