├── .gitignore ├── console ├── Worker.go ├── Register.go └── Gateway.go ├── config.ini ├── go.mod ├── protocol ├── Pack.go ├── Text.go └── GatewayProtocol.go ├── network ├── Protocol.go ├── Address.go ├── Client.go ├── TcpClient.go ├── TcpServer.go └── WebSocket.go ├── main.go ├── go.sum ├── gateway ├── RegisterEvent.go ├── WorkerRouter.go ├── WorkerServerEvent.go └── GatewayEvent.go └── register └── RegisterServerEvent.go /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | -------------------------------------------------------------------------------- /console/Worker.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | type Worker struct { 4 | } 5 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | ; 网关地址websocket 2 | gateway="127.0.0.1:8080" 3 | ; 注册中心 4 | register="127.0.0.1:1238" 5 | ; 内部通讯地址 6 | worker="127.0.0.1:4000" 7 | ; 通讯秘钥 8 | secret="" -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module GoGatewayWorker 2 | 3 | require ( 4 | github.com/ctfang/command v0.0.0-20190225130348-b3c29f95f8dc 5 | github.com/gorilla/websocket v1.4.0 6 | ) 7 | -------------------------------------------------------------------------------- /protocol/Pack.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | type Pack struct { 4 | } 5 | 6 | func (Pack)encode([]byte) { 7 | 8 | } 9 | 10 | func (Pack)decode() { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /network/Protocol.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import "bufio" 4 | 5 | type Protocol interface{ 6 | // 读入处理 7 | ReadString(reader *bufio.Reader) (interface{}, error) 8 | // 发送处理 9 | WriteString(msg interface{}) []byte 10 | } 11 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "GoGatewayWorker/console" 5 | "github.com/ctfang/command" 6 | ) 7 | 8 | func main() { 9 | app := command.New() 10 | 11 | app.SetConfig("D:\\GoLanProject\\GatewayWorker\\config.ini") 12 | app.IniConfig() 13 | 14 | AddCommands(&app) 15 | app.Run() 16 | } 17 | 18 | func AddCommands(app *command.Console) { 19 | app.AddCommand(console.Gateway{}) 20 | app.AddCommand(console.Register{}) 21 | } -------------------------------------------------------------------------------- /protocol/Text.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import "bufio" 4 | 5 | type Text struct { 6 | } 7 | 8 | func (t Text) ReadString(reader *bufio.Reader) (interface{}, error) { 9 | msg,err := reader.ReadString('\n') 10 | if err != nil { 11 | return msg,err 12 | } 13 | msg = msg[1:] 14 | return msg,err 15 | } 16 | 17 | func (t Text) WriteString(msg interface{}) []byte { 18 | strMsg := msg.(string) + "\n" 19 | return []byte(strMsg) 20 | } -------------------------------------------------------------------------------- /network/Address.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | type Address struct { 9 | Str string 10 | Ip string 11 | Port uint16 12 | } 13 | 14 | func NewAddress(addr string) *Address { 15 | strS := strings.Split(addr, ":") 16 | if len(strS) != 2 { 17 | panic("格式错误") 18 | } 19 | Port, _ := strconv.ParseInt(strS[1], 10, 64) 20 | return &Address{ 21 | Str: addr, 22 | Ip: strS[0], 23 | Port: uint16(Port), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/ctfang/command v0.0.0-20190214090442-521b850522a6 h1:ZXz5rqUgKCDuFfv3+Gt3dJ1ZB6f0jBsZGHbTitDihJA= 2 | github.com/ctfang/command v0.0.0-20190214090442-521b850522a6/go.mod h1:iWJcUCwZReswQ7T5IaRE6ZvGzZ/m9v53Z1na20JttV8= 3 | github.com/ctfang/command v0.0.0-20190222071816-3f41dba3eaad h1:mVUXx9UvW6Yg39stuMMsn52na49xzt5wimJ7/qJNw44= 4 | github.com/ctfang/command v0.0.0-20190222071816-3f41dba3eaad/go.mod h1:iWJcUCwZReswQ7T5IaRE6ZvGzZ/m9v53Z1na20JttV8= 5 | github.com/ctfang/command v0.0.0-20190223055504-7682f822e4d0 h1:qdeI7+IYefipey4zaOJQp4m4UlYwByBJITi0e2nIfj8= 6 | github.com/ctfang/command v0.0.0-20190223055504-7682f822e4d0/go.mod h1:iWJcUCwZReswQ7T5IaRE6ZvGzZ/m9v53Z1na20JttV8= 7 | github.com/ctfang/command v0.0.0-20190225130348-b3c29f95f8dc h1:UneLP0DQxidMi9DzNUFy3ShdjQHVwIYFIp8OHZucqqY= 8 | github.com/ctfang/command v0.0.0-20190225130348-b3c29f95f8dc/go.mod h1:iWJcUCwZReswQ7T5IaRE6ZvGzZ/m9v53Z1na20JttV8= 9 | github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= 10 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 11 | -------------------------------------------------------------------------------- /console/Register.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "GoGatewayWorker/gateway" 5 | "GoGatewayWorker/network" 6 | "GoGatewayWorker/protocol" 7 | "GoGatewayWorker/register" 8 | "github.com/ctfang/command" 9 | ) 10 | 11 | type Register struct { 12 | } 13 | 14 | func (Register) Configure() command.Configure { 15 | return command.Configure{ 16 | Name: "register", 17 | Description: "注册中心", 18 | Input: command.Argument{ 19 | Has: []command.ArgParam{ 20 | {Name: "-d", Description: "是否使用守护进程"}, 21 | }, 22 | Argument: []command.ArgParam{ 23 | {Name: "runType", Description: "执行操作:start、stop、status"}, 24 | }, 25 | Option: []command.ArgParam{ 26 | {Name: "addr", Description: "手动设置地址"}, 27 | }, 28 | }, 29 | } 30 | } 31 | 32 | func (Register) Execute(input command.Input) { 33 | gateway.RegisterAddress = network.NewAddress(input.GetOption("register")) 34 | gateway.SecretKey = input.GetOption("secret") 35 | 36 | tcp := network.TcpServer{} 37 | tcp.SetAddress(gateway.RegisterAddress) 38 | tcp.SetProtocol(protocol.Text{}) 39 | tcp.SetEvent(register.NewRegisterServerEvent()) 40 | tcp.ListenAndServe() 41 | } 42 | -------------------------------------------------------------------------------- /gateway/RegisterEvent.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "GoGatewayWorker/network" 5 | "encoding/json" 6 | "fmt" 7 | "log" 8 | "time" 9 | ) 10 | 11 | var GatewayAddress *network.Address 12 | var WorkerAddress *network.Address 13 | var RegisterAddress *network.Address 14 | var SecretKey string 15 | 16 | /* 17 | 连接注册中心客户端 18 | */ 19 | type RegisterEvent struct { 20 | // 内部通讯地址 21 | } 22 | 23 | type ConList struct { 24 | Event string `json:"event"` 25 | Address string `json:"address"` 26 | SecretKey string `json:"secret_key"` 27 | } 28 | 29 | func (r *RegisterEvent) OnConnect(clint *network.TcpServerConnection) { 30 | conData := ConList{ 31 | Event: "gateway_connect", 32 | Address: WorkerAddress.Str, 33 | SecretKey: SecretKey, 34 | } 35 | byteStr, _ := json.Marshal(conData) 36 | go clint.Send(string(byteStr)) 37 | log.Println("已经连接注册中心", clint.Addr) 38 | } 39 | 40 | func (*RegisterEvent) OnMessage(clint *network.TcpServerConnection, message interface{}) { 41 | fmt.Println(message) 42 | } 43 | 44 | // 关闭 45 | func (*RegisterEvent) OnClose(clint *network.TcpServerConnection) { 46 | // 注册中心 关闭,定时检查 47 | log.Print("注册中心 关闭,定时检查") 48 | ticker := time.NewTicker(time.Second * 2) 49 | for { 50 | select { 51 | case <-ticker.C: 52 | err := clint.Connect() 53 | if err == nil { 54 | ticker.Stop() 55 | return 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /console/Gateway.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "GoGatewayWorker/gateway" 5 | "GoGatewayWorker/network" 6 | "github.com/ctfang/command" 7 | ) 8 | 9 | type Gateway struct { 10 | } 11 | 12 | func (Gateway) Configure() command.Configure { 13 | return command.Configure{ 14 | Name: "gateway", 15 | Description: "网关进程gateway", 16 | Input: command.Argument{ 17 | Has: []command.ArgParam{ 18 | {Name: "-d", Description: "是否使用守护进程"}, 19 | }, 20 | Argument: []command.ArgParam{ 21 | {Name: "runType", Description: "执行操作:start、stop、status"}, 22 | }, 23 | Option: []command.ArgParam{ 24 | {Name: "gateway", Default: "127.0.0.1:8080", Description: "网关地址websocket"}, 25 | {Name: "register", Default: "127.0.0.1:1238", Description: "注册中心"}, 26 | {Name: "worker", Default: "127.0.0.1:4000", Description: "内部通讯地址"}, 27 | {Name: "secret", Default: "", Description: "通讯秘钥"}, 28 | }, 29 | }, 30 | } 31 | } 32 | 33 | func (Gateway) Execute(input command.Input) { 34 | 35 | gateway.GatewayAddress = network.NewAddress(input.GetOption("gateway")) 36 | gateway.WorkerAddress = network.NewAddress(input.GetOption("worker")) 37 | gateway.RegisterAddress = network.NewAddress(input.GetOption("register")) 38 | gateway.SecretKey = input.GetOption("secret") 39 | 40 | ws := network.WebSocket{ 41 | Addr: gateway.GatewayAddress, 42 | Event: &gateway.GatewayEvent{}, 43 | } 44 | ws.ListenAndServe() 45 | } 46 | -------------------------------------------------------------------------------- /gateway/WorkerRouter.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "GoGatewayWorker/network" 5 | "errors" 6 | ) 7 | 8 | type WorkerRouter struct { 9 | // 消费者 worker 注册列表 10 | workers map[uint32]*network.TcpServerClient 11 | 12 | // client 列表 13 | Clients map[uint32]*network.TcpClientConnection 14 | // client ConnectionId 映射 worker id 15 | clientList map[uint32]uint32 16 | } 17 | 18 | var Router = &WorkerRouter{ 19 | workers: map[uint32]*network.TcpServerClient{}, 20 | clientList: map[uint32]uint32{}, 21 | Clients: map[uint32]*network.TcpClientConnection{}, 22 | } 23 | 24 | func (w *WorkerRouter)GetWorker(c *network.TcpClientConnection)*network.TcpServerClient{ 25 | workerId := w.clientList[c.GetConnectionId()] 26 | return w.workers[workerId] 27 | } 28 | 29 | func (w *WorkerRouter)AddedWorker(worker *network.TcpServerClient){ 30 | w.workers[worker.Id] = worker 31 | } 32 | 33 | /** 34 | worker 断开 35 | */ 36 | func (w *WorkerRouter)DeleteWorker(worker *network.TcpServerClient){ 37 | delete(w.workers, worker.Id) 38 | for clientId, workerId := range w.clientList { 39 | if workerId == worker.Id { 40 | delete(w.clientList, clientId) 41 | } 42 | } 43 | } 44 | 45 | /** 46 | 新增客户端,并且建立路由映射 47 | */ 48 | func (w *WorkerRouter)AddedClient(c *network.TcpClientConnection) (uint32,error){ 49 | for workerId, _ := range w.workers { 50 | w.clientList[c.GetConnectionId()] = workerId 51 | w.Clients[c.GetConnectionId()] = c 52 | return workerId, nil 53 | } 54 | var err = errors.New("未有worker连接") 55 | return uint32(0), err 56 | } 57 | 58 | func (w *WorkerRouter)GetClient(ConnectionId uint32)(*network.TcpClientConnection,error){ 59 | c, ok := w.Clients[ConnectionId] 60 | if ok { 61 | return c, nil 62 | } 63 | 64 | return nil, errors.New("客户端不存在") 65 | } 66 | 67 | /** 68 | 删除 客户端 69 | */ 70 | func (w *WorkerRouter)DeleteClient(ConnectionId uint32){ 71 | delete(w.clientList, ConnectionId) 72 | delete(w.Clients, ConnectionId) 73 | } 74 | -------------------------------------------------------------------------------- /network/Client.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "github.com/gorilla/websocket" 5 | "net" 6 | "regexp" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | const ( 12 | // Time allowed to write a message to the peer. 13 | writeWait = 10 * time.Second 14 | 15 | // Time allowed to read the next pong message from the peer. 16 | pongWait = 60 * time.Second 17 | 18 | // Send pings to peer with this period. Must be less than pongWait. 19 | pingPeriod = (pongWait * 9) / 10 20 | 21 | // Maximum message size allowed from peer. 22 | maxMessageSize = 512 23 | ) 24 | 25 | var ( 26 | newline = []byte{'\n'} 27 | space = []byte{' '} 28 | ) 29 | 30 | // websocket client 31 | type TcpClientConnection struct { 32 | // 进程内唯一,递增 33 | id uint32 34 | // 连接唯一,分布 35 | uid string 36 | // The websocket connection. 37 | conn *websocket.Conn 38 | // Buffered channel of outbound messages. 39 | send chan []byte 40 | // 扩展对象 41 | Extend interface{} 42 | } 43 | 44 | func (c *TcpClientConnection) Close() { 45 | c.conn.Close() 46 | } 47 | 48 | func (c *TcpClientConnection) Send(meg []byte) { 49 | c.send <- meg 50 | } 51 | 52 | // 进程内id 53 | func (c *TcpClientConnection) GetConnectionId() uint32 { 54 | return c.id 55 | } 56 | 57 | // 唯一id 58 | func (c *TcpClientConnection) SetUid(str string) { 59 | c.uid = str 60 | } 61 | 62 | // 唯一id 63 | func (c *TcpClientConnection) GetUid() string { 64 | return c.uid 65 | } 66 | 67 | func (c *TcpClientConnection) GetRemoteAddr() net.Addr { 68 | return c.conn.RemoteAddr() 69 | } 70 | 71 | func (c *TcpClientConnection) GetPort() (port uint16) { 72 | ipStr := c.conn.RemoteAddr().String() 73 | r := `\:(\d{1,5})` 74 | reg, err := regexp.Compile(r) 75 | if err != nil { 76 | return 0 77 | } 78 | ips := reg.FindStringSubmatch(ipStr) 79 | if ips == nil { 80 | return 0 81 | } 82 | temp, _ := strconv.Atoi(ips[1]) 83 | port = uint16(temp) 84 | return 85 | } 86 | 87 | func (c *TcpClientConnection) GetIp() (ip string) { 88 | ipStr := c.conn.RemoteAddr().String() 89 | r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})` 90 | reg, err := regexp.Compile(r) 91 | if err != nil { 92 | return "" 93 | } 94 | ips := reg.FindStringSubmatch(ipStr) 95 | if ips == nil { 96 | return "" 97 | } 98 | 99 | return ips[0] 100 | } -------------------------------------------------------------------------------- /network/TcpClient.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "bufio" 5 | "log" 6 | "net" 7 | "regexp" 8 | "strconv" 9 | ) 10 | 11 | type TcpEventInterface interface { 12 | OnConnect(clint *TcpServerConnection) 13 | OnMessage(clint *TcpServerConnection, message interface{}) 14 | OnClose(clint *TcpServerConnection) 15 | } 16 | 17 | type TcpServerConnection struct { 18 | Addr *Address 19 | conn net.Conn 20 | Protocol Protocol 21 | Event TcpEventInterface 22 | SendChan chan []byte 23 | } 24 | 25 | func (t *TcpServerConnection) Connect()error { 26 | tcpAddr, err := net.ResolveTCPAddr("tcp4", t.Addr.Str); 27 | conn, err := net.DialTCP("tcp", nil,tcpAddr) 28 | 29 | if err != nil { 30 | log.Printf("connect failed, err : %v\n", err.Error()) 31 | return err 32 | } 33 | t.conn = conn 34 | 35 | go t.Event.OnConnect(t) 36 | go t.readPump() 37 | go t.writePump() 38 | return nil 39 | } 40 | 41 | func (t *TcpServerConnection) writePump() { 42 | defer t.Close() 43 | for { 44 | select { 45 | case text := <-t.SendChan: 46 | _, err := t.conn.Write(text) 47 | if err != nil { 48 | log.Println("Error writing to stream.",err) 49 | break 50 | } 51 | } 52 | } 53 | } 54 | 55 | func (t *TcpServerConnection) readPump() { 56 | reader := bufio.NewReader(t.conn) 57 | for { 58 | message, err := t.Protocol.ReadString(reader) 59 | if err != nil { 60 | t.Close() 61 | break 62 | } 63 | go t.Event.OnMessage(t, message) 64 | } 65 | } 66 | 67 | func (t *TcpServerConnection) Send(str string) { 68 | t.SendChan <- []byte(t.Protocol.WriteString(str)) 69 | } 70 | 71 | func (t *TcpServerConnection) Close() { 72 | t.conn.Close() 73 | t.Event.OnClose(t) 74 | } 75 | 76 | func Ip2long(ipstr string) (ip uint32) { 77 | r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})` 78 | reg, err := regexp.Compile(r) 79 | if err != nil { 80 | return 81 | } 82 | ips := reg.FindStringSubmatch(ipstr) 83 | if ips == nil { 84 | return 85 | } 86 | 87 | ip1, _ := strconv.Atoi(ips[1]) 88 | ip2, _ := strconv.Atoi(ips[2]) 89 | ip3, _ := strconv.Atoi(ips[3]) 90 | ip4, _ := strconv.Atoi(ips[4]) 91 | 92 | if ip1>255 || ip2>255 || ip3>255 || ip4 > 255 { 93 | return 94 | } 95 | 96 | ip += uint32(ip1 * 0x1000000) 97 | ip += uint32(ip2 * 0x10000) 98 | ip += uint32(ip3 * 0x100) 99 | ip += uint32(ip4) 100 | 101 | return ip 102 | } 103 | -------------------------------------------------------------------------------- /gateway/WorkerServerEvent.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "GoGatewayWorker/network" 5 | "GoGatewayWorker/protocol" 6 | "fmt" 7 | "log" 8 | "time" 9 | ) 10 | 11 | /* 12 | worker内部通讯逻辑,接收worker发到客户端信息 13 | */ 14 | type WorkerServerEvent struct { 15 | SendToWorker chan []byte 16 | } 17 | 18 | func (w *WorkerServerEvent) OnStart(tcp *network.TcpServer) { 19 | go w.connectRegister() 20 | w.SendToWorker = make(chan []byte,256) 21 | log.Println("已启动内部通讯",WorkerAddress.Str) 22 | } 23 | 24 | /* 25 | worker已连接网关 26 | */ 27 | func (*WorkerServerEvent) OnConnect(c *network.TcpServerClient) { 28 | 29 | } 30 | 31 | func (ws *WorkerServerEvent) OnMessage(c *network.TcpServerClient, message interface{}) { 32 | msg := message.(protocol.GatewayMessage) 33 | 34 | switch msg.Cmd { 35 | case protocol.CMD_ON_CONNECT: 36 | 37 | case protocol.CMD_ON_MESSAGE: 38 | case protocol.CMD_ON_CLOSE: 39 | ws.OnClose(c) 40 | case protocol.CMD_SEND_TO_ONE: 41 | // 单个用户信息 42 | ws.sendToOne(msg) 43 | case protocol.CMD_SEND_TO_ALL: 44 | // 发给gateway的向所有用户发送数据 45 | ws.sendToAll(msg) 46 | case protocol.CMD_WORKER_CONNECT: 47 | Router.AddedWorker(c) 48 | log.Println("worker已连接网关") 49 | default: 50 | log.Println(message) 51 | } 52 | } 53 | 54 | func (*WorkerServerEvent) sendToOne(msg protocol.GatewayMessage) { 55 | client,err := Router.GetClient(msg.ConnectionId) 56 | if err!=nil { 57 | Router.DeleteClient(msg.ConnectionId) 58 | return 59 | } 60 | 61 | client.Send([]byte(msg.Body)) 62 | } 63 | 64 | func (*WorkerServerEvent) sendToAll(msg protocol.GatewayMessage) { 65 | for _,client := range Router.Clients { 66 | client.Send([]byte(msg.Body)) 67 | } 68 | } 69 | 70 | /* 71 | 关闭 72 | */ 73 | func (w *WorkerServerEvent) OnClose(c *network.TcpServerClient) { 74 | Router.DeleteWorker(c) 75 | _ = c.Close() 76 | } 77 | 78 | 79 | func (w *WorkerServerEvent) SendToWorkerTask() { 80 | log.Println("implement me") 81 | } 82 | 83 | func (w *WorkerServerEvent) sendToWorker() { 84 | for { 85 | select { 86 | case message := <- w.SendToWorker: 87 | fmt.Println(message) 88 | } 89 | } 90 | } 91 | 92 | // 连接到注册中心 93 | func (w *WorkerServerEvent) connectRegister() { 94 | tcp := &network.TcpServerConnection{ 95 | Addr: RegisterAddress, 96 | Event: &RegisterEvent{}, 97 | Protocol: protocol.Text{}, 98 | SendChan: make(chan []byte, 256), 99 | } 100 | 101 | err := tcp.Connect() 102 | if err != nil { 103 | // 连接失败,添加定时器,定时请求 104 | ticker := time.NewTicker(time.Second * 2) 105 | for { 106 | select { 107 | case <-ticker.C: 108 | err := tcp.Connect() 109 | if err == nil { 110 | ticker.Stop() 111 | return 112 | } 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /network/TcpServer.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "log" 7 | "net" 8 | ) 9 | 10 | // UINT_MAX 11 | const MaxClient = ^uint32(0) 12 | 13 | type TcpServerClient struct { 14 | Id uint32 15 | conn net.Conn 16 | Server *TcpServer 17 | send chan []byte 18 | } 19 | 20 | type TcpServerEvent interface { 21 | OnStart(tcp *TcpServer) 22 | // 新链接 23 | OnConnect(c *TcpServerClient) 24 | // 新信息 25 | OnMessage(c *TcpServerClient, message interface{}) 26 | // 链接关闭 27 | OnClose(c *TcpServerClient) 28 | } 29 | 30 | type TcpServer struct { 31 | // 监听地址 32 | Address *Address 33 | // 解析格式 34 | protocol Protocol 35 | // 业务处理类 36 | event TcpServerEvent 37 | // 最新值id 38 | clientId uint32 39 | } 40 | 41 | // 设置监听地址 42 | func (t *TcpServer) SetAddress(address *Address) { 43 | t.Address = address 44 | } 45 | 46 | // 设置协议解析方式 47 | func (t *TcpServer) SetProtocol(protocol Protocol) { 48 | t.protocol = protocol 49 | } 50 | 51 | func (t *TcpServer) SetEvent(e TcpServerEvent) { 52 | t.event = e 53 | } 54 | 55 | // 开始监听 56 | func (t *TcpServer) ListenAndServe() { 57 | listener, err := net.Listen("tcp", t.Address.Str) 58 | if err != nil { 59 | log.Fatal("Error starting TCP server.") 60 | } 61 | defer listener.Close() 62 | go t.event.OnStart(t) 63 | for { 64 | conn, _ := listener.Accept() 65 | 66 | client := &TcpServerClient{ 67 | Id: t.MakeId(), 68 | conn: conn, 69 | Server: t, 70 | send: make(chan []byte, 256), 71 | } 72 | go t.listenClient(client) 73 | } 74 | } 75 | 76 | // 生产新id 77 | func (t *TcpServer) MakeId() uint32 { 78 | if t.clientId >= MaxClient { 79 | t.clientId = 0 80 | } 81 | t.clientId++ 82 | return t.clientId 83 | } 84 | 85 | func (t *TcpServer) listenClient(client *TcpServerClient) { 86 | // 出发链接事件 87 | t.event.OnConnect(client) 88 | go t.writePump(client) 89 | reader := bufio.NewReader(client.conn) 90 | for { 91 | message, err := t.protocol.ReadString(reader) 92 | if err != nil { 93 | _ = client.conn.Close() 94 | t.event.OnClose(client) 95 | return 96 | } 97 | t.event.OnMessage(client, message) 98 | } 99 | } 100 | 101 | func (t *TcpServer) writePump(client *TcpServerClient) { 102 | for { 103 | select { 104 | case message := <-client.send: 105 | _, err := client.conn.Write(message) 106 | if err != nil { 107 | fmt.Println("Error writing to stream.", err) 108 | break 109 | } 110 | } 111 | } 112 | } 113 | 114 | // Send text message to client 115 | func (c *TcpServerClient) Send(message interface{}) { 116 | byteMes := c.Server.protocol.WriteString(message) 117 | c.send <- byteMes 118 | } 119 | 120 | func (c *TcpServerClient) Close() error { 121 | return c.conn.Close() 122 | } 123 | -------------------------------------------------------------------------------- /gateway/GatewayEvent.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "GoGatewayWorker/network" 5 | "GoGatewayWorker/protocol" 6 | "encoding/binary" 7 | "encoding/hex" 8 | "log" 9 | ) 10 | 11 | /* 12 | 网关逻辑 13 | 转发数据到worker 14 | */ 15 | type GatewayEvent struct { 16 | WorkerServer *WorkerServerEvent 17 | } 18 | 19 | /** 20 | 客户端信息 21 | */ 22 | type GatewayHeader struct { 23 | // 内部通讯地址 , 对应本机地址 24 | LocalIp uint32 25 | LocalPort uint16 26 | ClientIp uint32 27 | ClientPort uint16 28 | GatewayPort uint16 29 | ConnectionId uint32 30 | flag uint8 31 | } 32 | 33 | func (g *GatewayEvent) OnStart() { 34 | // 启动一个内部通讯tcp server 35 | tcp := network.TcpServer{} 36 | worker := &WorkerServerEvent{} 37 | g.WorkerServer = worker 38 | tcp.SetAddress(WorkerAddress) 39 | tcp.SetProtocol(&protocol.GatewayProtocol{}) 40 | tcp.SetEvent(worker) 41 | tcp.ListenAndServe() 42 | } 43 | 44 | /* 45 | 有客户端连接 46 | */ 47 | func (g *GatewayEvent) OnConnect(client *network.TcpClientConnection) { 48 | client.SetUid(bin2hex(WorkerAddress.Ip,WorkerAddress.Port,client.GetConnectionId())) 49 | _, err := Router.AddedClient(client) 50 | if err != nil { 51 | log.Fatalln(err) 52 | g.OnClose(client) 53 | return 54 | } 55 | header := GatewayHeader{ 56 | LocalIp: network.Ip2long(WorkerAddress.Ip), 57 | LocalPort: WorkerAddress.Port, 58 | ClientIp: network.Ip2long(client.GetIp()), 59 | ClientPort: client.GetPort(), 60 | GatewayPort: GatewayAddress.Port, 61 | ConnectionId: client.GetConnectionId(), 62 | flag: 1, 63 | } 64 | client.Extend = header 65 | g.SendToWorker(client, protocol.CMD_ON_CONNECT, "") 66 | } 67 | 68 | // 构建分布式唯一id 69 | func bin2hex(ip string, port uint16, id uint32)string{ 70 | var msgByte []byte 71 | ipUint32 := network.Ip2long(ip) 72 | var buf32 = make([]byte, 4) 73 | var bug16 = make([]byte, 2) 74 | binary.BigEndian.PutUint32(buf32, ipUint32) 75 | msgByte = append(msgByte, buf32...) 76 | binary.BigEndian.PutUint16(bug16, port) 77 | msgByte = append(msgByte, bug16...) 78 | binary.BigEndian.PutUint32(buf32, id) 79 | msgByte = append(msgByte, buf32...) 80 | return hex.EncodeToString(msgByte) 81 | } 82 | 83 | // 客户端信息转发到worker处理 84 | func (g *GatewayEvent) OnMessage(clint *network.TcpClientConnection, message []byte) { 85 | body := string(message) 86 | g.SendToWorker(clint, protocol.CMD_ON_MESSAGE, body) 87 | } 88 | 89 | func (GatewayEvent) OnClose(clint *network.TcpClientConnection) { 90 | Router.DeleteClient(clint.GetConnectionId()) 91 | clint.Close() 92 | } 93 | 94 | func (g *GatewayEvent) SendToWorker(client *network.TcpClientConnection, cmd uint8, body string) { 95 | GatewayHeader := client.Extend.(GatewayHeader) 96 | msg := protocol.GatewayMessage{ 97 | PackageLen: 28 + uint32(len(body)), 98 | Cmd: cmd, 99 | LocalIp: GatewayHeader.LocalIp, 100 | LocalPort: GatewayHeader.LocalPort, 101 | ClientIp: GatewayHeader.ClientIp, 102 | ClientPort: GatewayHeader.ClientPort, 103 | ConnectionId: GatewayHeader.ConnectionId, 104 | Flag: GatewayHeader.flag, 105 | GatewayPort: GatewayHeader.GatewayPort, 106 | ExtLen: 0, 107 | ExtData: "", 108 | Body: body, 109 | } 110 | 111 | worker := Router.GetWorker(client) 112 | worker.Send(msg) 113 | } -------------------------------------------------------------------------------- /register/RegisterServerEvent.go: -------------------------------------------------------------------------------- 1 | package register 2 | 3 | import ( 4 | "GoGatewayWorker/network" 5 | "encoding/json" 6 | "fmt" 7 | ) 8 | 9 | // 注册中心 10 | type RegisterServerEvent struct { 11 | // ID 地址保存 12 | gatewayConnections map[uint32]string 13 | workerConnections map[uint32]*network.TcpServerClient 14 | // 秘要 15 | SecretKey string 16 | } 17 | 18 | func NewRegisterServerEvent() *RegisterServerEvent { 19 | reg := RegisterServerEvent{ 20 | gatewayConnections: make(map[uint32]string), 21 | workerConnections: make(map[uint32]*network.TcpServerClient), 22 | } 23 | return ® 24 | } 25 | 26 | type RegisterMessage struct { 27 | Event string `json:"event"` 28 | Address string `json:"address"` 29 | SecretKey string `json:"secret_key"` 30 | } 31 | 32 | 33 | func (r *RegisterServerEvent) OnStart(tcp *network.TcpServer) { 34 | 35 | } 36 | 37 | // 新链接 38 | func (r *RegisterServerEvent) OnConnect(c *network.TcpServerClient) { 39 | // 40 | c.Send("1") 41 | c.Send("2") 42 | } 43 | 44 | // 新信息 45 | func (r *RegisterServerEvent) OnMessage(c *network.TcpServerClient, msg interface{}) { 46 | var data RegisterMessage 47 | err := json.Unmarshal([]byte(msg.(string)), &data) 48 | if err != nil { 49 | fmt.Println(err) 50 | _ = c.Close() 51 | return 52 | } 53 | if r.SecretKey != "" { 54 | if data.SecretKey != r.SecretKey { 55 | fmt.Println("秘要不对") 56 | _ = c.Close() 57 | return 58 | } 59 | } 60 | 61 | switch data.Event { 62 | case "gateway_connect": 63 | r.gatewayConnect(c, data) 64 | case "worker_connect": 65 | r.workerConnect(c, data) 66 | case "ping": 67 | return 68 | default: 69 | fmt.Println("不认识的事件定义") 70 | _ = c.Close() 71 | } 72 | } 73 | 74 | // 链接关闭 75 | func (r *RegisterServerEvent) OnClose(c *network.TcpServerClient) { 76 | _, hasG := r.gatewayConnections[c.Id] 77 | if hasG == true { 78 | delete(r.gatewayConnections, c.Id) 79 | r.broadcastAddresses(0) 80 | } 81 | 82 | _, hasW := r.workerConnections[c.Id] 83 | if hasW == true { 84 | delete(r.workerConnections, c.Id) 85 | } 86 | } 87 | 88 | // gateway 链接 89 | func (r *RegisterServerEvent) gatewayConnect(c *network.TcpServerClient, msg RegisterMessage) { 90 | if msg.Address == "" { 91 | println("address not found") 92 | _ = c.Close() 93 | return 94 | } 95 | // 推入列表 96 | r.gatewayConnections[c.Id] = msg.Address 97 | r.broadcastAddresses(0) 98 | } 99 | 100 | // worker 链接 101 | func (r *RegisterServerEvent) workerConnect(c *network.TcpServerClient, msg RegisterMessage) { 102 | // 推入列表 103 | r.workerConnections[c.Id] = c 104 | r.broadcastAddresses(0) 105 | } 106 | 107 | /* 108 | 向 BusinessWorker 广播 gateway 内部通讯地址 109 | 0 全部发生 110 | */ 111 | func (r *RegisterServerEvent) broadcastAddresses(id uint32) { 112 | type ConList struct { 113 | Event string `json:"event"` 114 | Addresses []string `json:"addresses"` 115 | } 116 | data := ConList{Event: "broadcast_addresses"} 117 | 118 | for _, address := range r.gatewayConnections { 119 | data.Addresses = append(data.Addresses, address) 120 | } 121 | 122 | jsonByte, _ := json.Marshal(data) 123 | sendMsg := string(jsonByte) 124 | 125 | if id != 0 { 126 | worker := r.workerConnections[id] 127 | worker.Send(sendMsg) 128 | return 129 | } 130 | 131 | for _, worker := range r.workerConnections { 132 | worker.Send(sendMsg) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /network/WebSocket.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "bytes" 5 | "github.com/gorilla/websocket" 6 | "log" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | type WebSocket struct { 12 | Addr *Address 13 | upgrader websocket.Upgrader 14 | Event WsEventInterface 15 | // 最新值id 16 | clientId uint32 17 | } 18 | 19 | type WsEventInterface interface { 20 | // 启动前 21 | OnStart() 22 | // 有客户端连接 23 | OnConnect(clint *TcpClientConnection) 24 | // 有信息 25 | OnMessage(clint *TcpClientConnection, message []byte) 26 | // 关闭 27 | OnClose(clint *TcpClientConnection) 28 | } 29 | 30 | // 开启监听 31 | func (ws *WebSocket) ListenAndServe() { 32 | ws.upgrader = websocket.Upgrader{ 33 | ReadBufferSize: 1024, 34 | WriteBufferSize: 1024, 35 | CheckOrigin: func(r *http.Request) bool { 36 | return true 37 | }, 38 | } 39 | go ws.Event.OnStart() 40 | 41 | http.HandleFunc("/", ws.Upgrade) 42 | err := http.ListenAndServe(ws.Addr.Str, nil) 43 | if err != nil { 44 | log.Fatal("ListenAndServe: ", err) 45 | } 46 | } 47 | 48 | // 生产新id 49 | func (w *WebSocket) MakeId() uint32 { 50 | if w.clientId >= MaxClient { 51 | w.clientId = 0 52 | } 53 | w.clientId++ 54 | return w.clientId 55 | } 56 | 57 | func (ws *WebSocket) Upgrade(w http.ResponseWriter, r *http.Request) { 58 | conn, err := ws.upgrader.Upgrade(w, r, nil) 59 | if err != nil { 60 | log.Println(err) 61 | return 62 | } 63 | client := &TcpClientConnection{ 64 | conn: conn, 65 | send: make(chan []byte, 256), 66 | id: ws.MakeId(), 67 | } 68 | 69 | go ws.Event.OnConnect(client) 70 | go ws.writePump(client) 71 | go ws.readPump(client) 72 | } 73 | 74 | func (ws *WebSocket) writePump(c *TcpClientConnection) { 75 | defer ws.Event.OnClose(c) 76 | 77 | ticker := time.NewTicker(pingPeriod) 78 | 79 | for { 80 | select { 81 | case message, ok := <-c.send: 82 | _ = c.conn.SetWriteDeadline(time.Now().Add(writeWait)) 83 | if !ok { 84 | _ = c.conn.WriteMessage(websocket.CloseMessage, []byte{}) 85 | return 86 | } 87 | w, err := c.conn.NextWriter(websocket.TextMessage) 88 | if err != nil { 89 | return 90 | } 91 | 92 | w.Write(message) 93 | 94 | // Add queued chat messages to the current websocket message. 95 | n := len(c.send) 96 | for i := 0; i < n; i++ { 97 | w.Write(newline) 98 | w.Write(<-c.send) 99 | } 100 | 101 | if err := w.Close(); err != nil { 102 | return 103 | } 104 | case <-ticker.C: 105 | _ = c.conn.SetWriteDeadline(time.Now().Add(writeWait)) 106 | if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil { 107 | return 108 | } 109 | } 110 | } 111 | } 112 | 113 | func (ws *WebSocket) readPump(c *TcpClientConnection) { 114 | defer ws.Event.OnClose(c) 115 | 116 | // 信息size上限 117 | c.conn.SetReadLimit(maxMessageSize) 118 | // 设置底层网络连接的读取截止日期。读取超时后,websocket连接状态已损坏,所有将来的读取都将返回错误。t的零值意味着读取不会超时。 119 | c.conn.SetReadDeadline(time.Now().Add(pongWait)) 120 | // Pong 信息 121 | c.conn.SetPongHandler(func(string) error { _ = c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) 122 | for { 123 | _, message, err := c.conn.ReadMessage() 124 | if err != nil { 125 | //if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { 126 | // log.Printf("error: %v", err) 127 | //} 128 | break 129 | } 130 | message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1)) 131 | go ws.Event.OnMessage(c, message) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /protocol/GatewayProtocol.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "bufio" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "reflect" 9 | ) 10 | 11 | // 发给worker,gateway有一个新的连接 12 | const CMD_ON_CONNECT = 1; 13 | 14 | // 发给worker的,客户端有消息 15 | const CMD_ON_MESSAGE = 3; 16 | 17 | // 发给worker上的关闭链接事件 18 | const CMD_ON_CLOSE = 4; 19 | 20 | // 发给gateway的向单个用户发送数据 21 | const CMD_SEND_TO_ONE = 5; 22 | 23 | // 发给gateway的向所有用户发送数据 24 | const CMD_SEND_TO_ALL = 6; 25 | 26 | // 发给gateway的踢出用户 27 | // 1、如果有待发消息,将在发送完后立即销毁用户连接 28 | // 2、如果无待发消息,将立即销毁用户连接 29 | const CMD_KICK = 7; 30 | 31 | // 发给gateway的立即销毁用户连接 32 | const CMD_DESTROY = 8; 33 | 34 | // 发给gateway,通知用户session更新 35 | const CMD_UPDATE_SESSION = 9; 36 | 37 | // 获取在线状态 38 | const CMD_GET_ALL_CLIENT_SESSIONS = 10; 39 | 40 | // 判断是否在线 41 | const CMD_IS_ONLINE = 11; 42 | 43 | // client_id绑定到uid 44 | const CMD_BIND_UID = 12; 45 | 46 | // 解绑 47 | const CMD_UNBIND_UID = 13; 48 | 49 | // 向uid发送数据 50 | const CMD_SEND_TO_UID = 14; 51 | 52 | // 根据uid获取绑定的clientid 53 | const CMD_GET_CLIENT_ID_BY_UID = 15; 54 | 55 | // 加入组 56 | const CMD_JOIN_GROUP = 20; 57 | 58 | // 离开组 59 | const CMD_LEAVE_GROUP = 21; 60 | 61 | // 向组成员发消息 62 | const CMD_SEND_TO_GROUP = 22; 63 | 64 | // 获取组成员 65 | const CMD_GET_CLIENT_SESSIONS_BY_GROUP = 23; 66 | 67 | // 获取组在线连接数 68 | const CMD_GET_CLIENT_COUNT_BY_GROUP = 24; 69 | 70 | // 按照条件查找 71 | const CMD_SELECT = 25; 72 | 73 | // 获取在线的群组ID 74 | const CMD_GET_GROUP_ID_LIST = 26; 75 | 76 | // 取消分组 77 | const CMD_UNGROUP = 27; 78 | 79 | // worker连接gateway事件 80 | const CMD_WORKER_CONNECT = 200; 81 | 82 | // 心跳 83 | const CMD_PING = 201; 84 | 85 | // GatewayClient连接gateway事件 86 | const CMD_GATEWAY_CLIENT_CONNECT = 202; 87 | 88 | // 根据client_id获取session 89 | const CMD_GET_SESSION_BY_CLIENT_ID = 203; 90 | 91 | // 发给gateway,覆盖session 92 | const CMD_SET_SESSION = 204; 93 | 94 | // 当websocket握手时触发,只有websocket协议支持此命令字 95 | const CMD_ON_WEBSOCKET_CONNECT = 205; 96 | 97 | // 包体是标量 98 | const FLAG_BODY_IS_SCALAR = 0x01; 99 | 100 | // 通知gateway在send时不调用协议encode方法,在广播组播时提升性能 101 | const FLAG_NOT_CALL_ENCODE = 0x02; 102 | 103 | 104 | type GatewayProtocol struct { 105 | cacheLen int 106 | cacheReader []byte 107 | } 108 | // "Npack_len/Ccmd/Nlocal_ip/nlocal_port/Nclient_ip/nclient_port/Nconnection_id/Cflag/ngateway_port/Next_len" 109 | type GatewayMessage struct { 110 | PackageLen uint32 111 | Cmd uint8 112 | LocalIp uint32 113 | LocalPort uint16 114 | ClientIp uint32 115 | ClientPort uint16 116 | ConnectionId uint32 117 | Flag uint8 118 | GatewayPort uint16 119 | 120 | ExtLen uint32 121 | ExtData string 122 | Body string 123 | } 124 | 125 | func (t *GatewayProtocol) ReadString(reader *bufio.Reader) (interface{}, error) { 126 | if t.cacheLen > 0 { 127 | data := t.cacheReader 128 | dataLen := t.cacheLen 129 | t.cacheLen = 0 130 | t.cacheReader = []byte{} 131 | 132 | // 包长度,不足重新读取 133 | if dataLen < 4 { 134 | dataTem := make([]byte, 1024) 135 | dataLenTem, err := reader.Read(dataTem) 136 | if err != nil { 137 | return nil, err 138 | } 139 | dataLen = dataLen + dataLenTem 140 | data = append(dataTem) 141 | } 142 | // 包长度大于实际数据长度,还有数据未传完整 143 | PackageLen := uint32(binary.BigEndian.Uint32(data[0:4])) 144 | intPackageLen := int(PackageLen) 145 | if intPackageLen > dataLen { 146 | // 实际数据不足 147 | t.cacheLen = dataLen 148 | t.cacheReader = data 149 | return t.ReadString(reader) 150 | } else if intPackageLen == dataLen { 151 | return t.ReadStruct(data), nil 152 | } else if intPackageLen < dataLen { 153 | // 实际比需要的长 154 | t.cacheLen = dataLen - intPackageLen 155 | t.cacheReader = data[intPackageLen:] 156 | return t.ReadStruct(data), nil 157 | } 158 | } else { 159 | data := make([]byte, 1024) 160 | 161 | dataLen, err := reader.Read(data) 162 | if err != nil { 163 | return nil, err 164 | } 165 | // 包长度,不足直接抛弃连接 166 | if dataLen < 4 { 167 | return nil, err 168 | } 169 | // 包长度大于实际数据长度,还有数据未传完整 170 | PackageLen := uint32(binary.BigEndian.Uint32(data[0:4])) 171 | intPackageLen := int(PackageLen) 172 | if intPackageLen > dataLen { 173 | // 实际数据不足 174 | t.cacheLen = dataLen 175 | t.cacheReader = data 176 | return t.ReadString(reader) 177 | } else if intPackageLen == dataLen { 178 | return t.ReadStruct(data), nil 179 | } else if intPackageLen < dataLen { 180 | // 实际比需要的长 181 | t.cacheLen = dataLen - intPackageLen 182 | t.cacheReader = data[intPackageLen:] 183 | return t.ReadStruct(data), nil 184 | } 185 | } 186 | return nil, errors.New("不能解析") 187 | } 188 | 189 | type SliceMock struct { 190 | addr uintptr 191 | len int 192 | cap int 193 | } 194 | 195 | func (t *GatewayProtocol) WriteString(msg interface{}) []byte { 196 | var msgByte []byte 197 | 198 | value := reflect.ValueOf(msg) 199 | for i := 0; i < value.NumField(); i++ { 200 | field := value.Field(i) 201 | switch field.Kind() { 202 | case reflect.String: 203 | var bufStr []byte 204 | bufStr = []byte(field.String()) 205 | msgByte = append(msgByte, bufStr...) 206 | case reflect.Uint8: 207 | msgByte = append(msgByte, uint8(field.Uint())) 208 | case reflect.Uint16: 209 | var buf16 = make([]byte, 2) 210 | binary.BigEndian.PutUint16(buf16, uint16(field.Uint())) 211 | msgByte = append(msgByte, buf16...) 212 | case reflect.Uint32: 213 | var buf32 = make([]byte, 4) 214 | binary.BigEndian.PutUint32(buf32, uint32(field.Uint())) 215 | msgByte = append(msgByte, buf32...) 216 | default: 217 | fmt.Println("不知道的类型",field.Type()) 218 | } 219 | } 220 | 221 | return msgByte 222 | } 223 | 224 | func (t *GatewayProtocol) ReadStruct(data []byte) GatewayMessage { 225 | Message := GatewayMessage{ 226 | PackageLen: uint32(binary.BigEndian.Uint32(data[0:4])), 227 | Cmd: data[4], 228 | LocalIp: uint32(binary.BigEndian.Uint32(data[5:9])), 229 | LocalPort: uint16(binary.BigEndian.Uint16(data[9:11])), 230 | ClientIp: uint32(binary.BigEndian.Uint32(data[11:15])), 231 | ClientPort: uint16(binary.BigEndian.Uint16(data[15:17])), 232 | ConnectionId: uint32(binary.BigEndian.Uint32(data[17:21])), 233 | Flag: data[21], 234 | GatewayPort: uint16(binary.BigEndian.Uint16(data[22:24])), 235 | ExtLen: uint32(binary.BigEndian.Uint32(data[24:28])), 236 | } 237 | Message.ExtData = string(data[28 : 28+Message.ExtLen]) 238 | Message.Body = string(data[(28+Message.ExtLen) : (Message.PackageLen)]) 239 | 240 | return Message 241 | } 242 | --------------------------------------------------------------------------------