├── README.md ├── tcpclient.go ├── service.go ├── tcpserver.go ├── bytebuffer.go └── tcptask.go /README.md: -------------------------------------------------------------------------------- 1 | # gonet 2 | 一个通用高效的游戏网络库 3 | -------------------------------------------------------------------------------- /tcpclient.go: -------------------------------------------------------------------------------- 1 | package gonet 2 | 3 | import ( 4 | "net" 5 | "time" 6 | ) 7 | 8 | type TcpClient struct { 9 | } 10 | 11 | func (this *TcpClient) Connect(address string) (*net.TCPConn, error) { 12 | 13 | tcpAddr, err := net.ResolveTCPAddr("tcp4", address) 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | conn, err := net.DialTCP("tcp", nil, tcpAddr) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | conn.SetKeepAlive(true) 24 | conn.SetKeepAlivePeriod(1 * time.Minute) 25 | conn.SetNoDelay(true) 26 | conn.SetWriteBuffer(128 * 1024) 27 | conn.SetReadBuffer(128 * 1024) 28 | 29 | return conn, nil 30 | } 31 | -------------------------------------------------------------------------------- /service.go: -------------------------------------------------------------------------------- 1 | package gonet 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "runtime" 8 | "runtime/debug" 9 | "syscall" 10 | ) 11 | 12 | type IService interface { 13 | Init() bool 14 | Reload() 15 | MainLoop() 16 | Final() bool 17 | } 18 | 19 | type Service struct { 20 | terminate bool 21 | Derived IService 22 | } 23 | 24 | func (this *Service) Terminate() { 25 | this.terminate = true 26 | } 27 | 28 | func (this *Service) isTerminate() bool { 29 | return this.terminate 30 | } 31 | 32 | func (this *Service) Main() bool { 33 | 34 | defer func() { 35 | if err := recover(); err != nil { 36 | fmt.Println("[异常] ", err, "\n", string(debug.Stack())) 37 | } 38 | }() 39 | 40 | ch := make(chan os.Signal, 1) 41 | signal.Notify(ch, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGABRT, syscall.SIGTERM, syscall.SIGPIPE, syscall.SIGHUP) 42 | go func() { 43 | for sig := range ch { 44 | switch sig { 45 | case syscall.SIGHUP: 46 | this.Derived.Reload() 47 | case syscall.SIGPIPE: 48 | default: 49 | this.Terminate() 50 | } 51 | fmt.Println("[服务] 收到信号 ", sig) 52 | } 53 | }() 54 | 55 | runtime.GOMAXPROCS(runtime.NumCPU()) 56 | 57 | if !this.Derived.Init() { 58 | return false 59 | } 60 | 61 | for !this.isTerminate() { 62 | this.Derived.MainLoop() 63 | } 64 | 65 | this.Derived.Final() 66 | return true 67 | } 68 | -------------------------------------------------------------------------------- /tcpserver.go: -------------------------------------------------------------------------------- 1 | package gonet 2 | 3 | import ( 4 | "net" 5 | "time" 6 | ) 7 | 8 | type TcpServer struct { 9 | listener *net.TCPListener 10 | } 11 | 12 | func (this *TcpServer) Bind(address string) error { 13 | 14 | tcpAddr, err := net.ResolveTCPAddr("tcp4", address) 15 | if err != nil { 16 | return err 17 | } 18 | 19 | listener, err := net.ListenTCP("tcp", tcpAddr) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | this.listener = listener 25 | return nil 26 | } 27 | 28 | func (this *TcpServer) BindAccept(address string, handler func(*net.TCPConn)) error { 29 | err := this.Bind(address) 30 | if err != nil { 31 | return err 32 | } 33 | go func() { 34 | for { 35 | conn, err := this.Accept() 36 | if err != nil { 37 | continue 38 | } 39 | handler(conn) 40 | } 41 | }() 42 | return nil 43 | } 44 | 45 | func (this *TcpServer) Accept() (*net.TCPConn, error) { 46 | 47 | this.listener.SetDeadline(time.Now().Add(time.Second * 1)) 48 | 49 | conn, err := this.listener.AcceptTCP() 50 | if err != nil { 51 | if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { 52 | return nil, err 53 | } 54 | return nil, err 55 | } 56 | 57 | conn.SetKeepAlive(true) 58 | conn.SetKeepAlivePeriod(1 * time.Minute) 59 | conn.SetNoDelay(true) 60 | conn.SetWriteBuffer(128 * 1024) 61 | conn.SetReadBuffer(128 * 1024) 62 | 63 | return conn, nil 64 | } 65 | 66 | func (this *TcpServer) Close() error { 67 | return this.listener.Close() 68 | } 69 | -------------------------------------------------------------------------------- /bytebuffer.go: -------------------------------------------------------------------------------- 1 | package gonet 2 | 3 | const ( 4 | presize = 0 5 | initsize = 10 6 | ) 7 | 8 | type ByteBuffer struct { 9 | _buffer []byte 10 | _prependSize int 11 | _readerIndex int 12 | _writerIndex int 13 | } 14 | 15 | func NewByteBuffer() *ByteBuffer { 16 | return &ByteBuffer{ 17 | _buffer: make([]byte, presize+initsize), 18 | _prependSize: presize, 19 | _readerIndex: presize, 20 | _writerIndex: presize, 21 | } 22 | } 23 | 24 | func (this *ByteBuffer) Append(buff ...byte) { 25 | size := len(buff) 26 | if size == 0 { 27 | return 28 | } 29 | this.WrGrow(size) 30 | copy(this._buffer[this._writerIndex:], buff) 31 | this.WrFlip(size) 32 | } 33 | 34 | func (this *ByteBuffer) WrBuf() []byte { 35 | if this._writerIndex >= len(this._buffer) { 36 | return nil 37 | } 38 | return this._buffer[this._writerIndex:] 39 | } 40 | 41 | func (this *ByteBuffer) WrSize() int { 42 | return len(this._buffer) - this._writerIndex 43 | } 44 | 45 | func (this *ByteBuffer) WrFlip(size int) { 46 | this._writerIndex += size 47 | } 48 | 49 | func (this *ByteBuffer) WrGrow(size int) { 50 | if size > this.WrSize() { 51 | this.wrreserve(size) 52 | } 53 | } 54 | 55 | func (this *ByteBuffer) RdBuf() []byte { 56 | if this._readerIndex >= len(this._buffer) { 57 | return nil 58 | } 59 | return this._buffer[this._readerIndex:] 60 | } 61 | 62 | func (this *ByteBuffer) RdReady() bool { 63 | return this._writerIndex > this._readerIndex 64 | } 65 | 66 | func (this *ByteBuffer) RdSize() int { 67 | return this._writerIndex - this._readerIndex 68 | } 69 | 70 | func (this *ByteBuffer) RdFlip(size int) { 71 | if size < this.RdSize() { 72 | this._readerIndex += size 73 | } else { 74 | this.Reset() 75 | } 76 | } 77 | 78 | func (this *ByteBuffer) Reset() { 79 | this._readerIndex = this._prependSize 80 | this._writerIndex = this._prependSize 81 | } 82 | 83 | func (this *ByteBuffer) MaxSize() int { 84 | return len(this._buffer) 85 | } 86 | 87 | func (this *ByteBuffer) wrreserve(size int) { 88 | if this.WrSize()+this._readerIndex < size+this._prependSize { 89 | tmpbuff := make([]byte, this._writerIndex+size) 90 | copy(tmpbuff, this._buffer) 91 | this._buffer = tmpbuff 92 | } else { 93 | readable := this.RdSize() 94 | copy(this._buffer[this._prependSize:], this._buffer[this._readerIndex:this._writerIndex]) 95 | this._readerIndex = this._prependSize 96 | this._writerIndex = this._readerIndex + readable 97 | } 98 | } 99 | 100 | func (this *ByteBuffer) Prepend(buff []byte) bool { 101 | size := len(buff) 102 | if this._readerIndex < size { 103 | return false 104 | } 105 | this._readerIndex -= size 106 | copy(this._buffer[this._readerIndex:], buff) 107 | return true 108 | } 109 | -------------------------------------------------------------------------------- /tcptask.go: -------------------------------------------------------------------------------- 1 | package gonet 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "runtime/debug" 8 | "sync" 9 | "sync/atomic" 10 | "time" 11 | ) 12 | 13 | type ITcpTask interface { 14 | ParseMsg(data []byte, flag byte) bool 15 | OnClose() 16 | } 17 | 18 | const ( 19 | cmd_max_size = 128 * 1024 20 | cmd_header_size = 4 // 3字节指令长度 1字节是否压缩 21 | cmd_verify_time = 10 22 | ) 23 | 24 | type TcpTask struct { 25 | closed int32 26 | verified bool 27 | stopedChan chan struct{} 28 | recvBuff *ByteBuffer 29 | sendBuff [][]byte 30 | sendMutex sync.Mutex 31 | sendChan chan bool 32 | Conn net.Conn 33 | Derived ITcpTask 34 | } 35 | 36 | func NewTcpTask(conn net.Conn) *TcpTask { 37 | return &TcpTask{ 38 | closed: -1, 39 | verified: false, 40 | Conn: conn, 41 | stopedChan: make(chan struct{}), 42 | recvBuff: NewByteBuffer(), 43 | sendChan: make(chan bool), 44 | } 45 | } 46 | 47 | func (this *TcpTask) RemoteAddr() string { 48 | if this.Conn == nil { 49 | return "" 50 | } 51 | return this.Conn.RemoteAddr().String() 52 | } 53 | 54 | func (this *TcpTask) Start() { 55 | if atomic.CompareAndSwapInt32(&this.closed, -1, 0) { 56 | job := &sync.WaitGroup{} 57 | job.Add(2) 58 | go this.sendloop(job) 59 | go this.recvloop(job) 60 | job.Wait() 61 | fmt.Println("[连接] 收到连接 ", this.RemoteAddr()) 62 | } 63 | } 64 | 65 | func (this *TcpTask) Close() { 66 | if atomic.CompareAndSwapInt32(&this.closed, 0, 1) { 67 | fmt.Println("[连接] 断开连接 ", this.RemoteAddr()) 68 | this.Conn.Close() 69 | close(this.stopedChan) 70 | close(this.sendChan) 71 | this.recvBuff.Reset() 72 | this.sendBuff = this.sendBuff[:0] 73 | this.Derived.OnClose() 74 | } 75 | } 76 | 77 | func (this *TcpTask) IsClosed() bool { 78 | return atomic.LoadInt32(&this.closed) != 0 79 | } 80 | 81 | func (this *TcpTask) Verify() { 82 | this.verified = true 83 | } 84 | 85 | func (this *TcpTask) IsVerified() bool { 86 | return this.verified 87 | } 88 | 89 | func (this *TcpTask) AsyncSend(buffer []byte, flag byte) bool { 90 | if this.IsClosed() { 91 | return false 92 | } 93 | bsize := len(buffer) 94 | header := []byte{byte(bsize), byte(bsize >> 8), byte(bsize >> 16), flag} 95 | this.sendMutex.Lock() 96 | this.sendBuff = append(this.sendBuff, header) 97 | this.sendBuff = append(this.sendBuff, buffer) 98 | this.sendMutex.Unlock() 99 | select { 100 | case this.sendChan <- true: 101 | default: 102 | } 103 | return true 104 | } 105 | 106 | func (this *TcpTask) recvloop(job *sync.WaitGroup) { 107 | defer func() { 108 | if err := recover(); err != nil { 109 | fmt.Println("[异常] ", err, "\n", string(debug.Stack())) 110 | } 111 | }() 112 | defer this.Close() 113 | 114 | var ( 115 | neednum int 116 | readnum int 117 | err error 118 | totalsize int 119 | datasize int 120 | msgbuff []byte 121 | ) 122 | 123 | job.Done() 124 | 125 | for { 126 | totalsize = this.recvBuff.RdSize() 127 | 128 | if totalsize < cmd_header_size { 129 | 130 | neednum = cmd_header_size - totalsize 131 | if this.recvBuff.WrSize() < neednum { 132 | this.recvBuff.WrGrow(neednum) 133 | } 134 | 135 | readnum, err = io.ReadAtLeast(this.Conn, this.recvBuff.WrBuf(), neednum) 136 | if err != nil { 137 | fmt.Println("[连接] 接收失败 ", this.RemoteAddr(), ",", err) 138 | return 139 | } 140 | 141 | this.recvBuff.WrFlip(readnum) 142 | totalsize = this.recvBuff.RdSize() 143 | } 144 | 145 | msgbuff = this.recvBuff.RdBuf() 146 | 147 | datasize = int(msgbuff[0]) | int(msgbuff[1])<<8 | int(msgbuff[2])<<16 148 | if datasize > cmd_max_size { 149 | fmt.Println("[连接] 数据超过最大值 ", this.RemoteAddr(), ",", datasize) 150 | return 151 | } 152 | 153 | if totalsize < cmd_header_size+datasize { 154 | 155 | neednum = cmd_header_size + datasize - totalsize 156 | if this.recvBuff.WrSize() < neednum { 157 | this.recvBuff.WrGrow(neednum) 158 | } 159 | 160 | readnum, err = io.ReadAtLeast(this.Conn, this.recvBuff.WrBuf(), neednum) 161 | if err != nil { 162 | fmt.Println("[连接] 接收失败 ", this.RemoteAddr(), ",", err) 163 | return 164 | } 165 | 166 | this.recvBuff.WrFlip(readnum) 167 | msgbuff = this.recvBuff.RdBuf() 168 | } 169 | 170 | this.Derived.ParseMsg(msgbuff[cmd_header_size:cmd_header_size+datasize], msgbuff[3]) 171 | this.recvBuff.RdFlip(cmd_header_size + datasize) 172 | } 173 | } 174 | 175 | func (this *TcpTask) sendloop(job *sync.WaitGroup) { 176 | var ( 177 | tmpByte = NewByteBuffer() 178 | timeout = time.NewTimer(time.Second * cmd_verify_time) 179 | writenum int 180 | err error 181 | ) 182 | 183 | defer func() { 184 | if err := recover(); err != nil { 185 | fmt.Println("[异常] ", err, "\n", string(debug.Stack())) 186 | } 187 | this.Close() 188 | timeout.Stop() 189 | }() 190 | 191 | job.Done() 192 | 193 | for { 194 | select { 195 | case <-this.sendChan: 196 | for { 197 | this.sendMutex.Lock() 198 | for _, buffer := range this.sendBuff { 199 | tmpByte.Append(buffer...) 200 | } 201 | this.sendBuff = this.sendBuff[:0] 202 | this.sendMutex.Unlock() 203 | if !tmpByte.RdReady() { 204 | break 205 | } 206 | writenum, err = this.Conn.Write(tmpByte.RdBuf()[:tmpByte.RdSize()]) 207 | if err != nil { 208 | fmt.Println("[连接] 发送失败 ", this.RemoteAddr(), ",", err) 209 | return 210 | } 211 | tmpByte.RdFlip(writenum) 212 | } 213 | case <-this.stopedChan: 214 | return 215 | case <-timeout.C: 216 | if !this.IsVerified() { 217 | fmt.Println("[连接] 验证超时 ", this.RemoteAddr()) 218 | return 219 | } 220 | } 221 | } 222 | } 223 | --------------------------------------------------------------------------------