分析见注释
1 cgss.go
package main import ( "bufio" "cg" "fmt" "ipc" "os" "strconv" "strings" ) var centerClient *cg.CenterClient func startCenterService() error { //step comment:1,CenterServer 实现了Server 接口,NewIpcServer也建立了和server.go中server.handler()建立 server := ipc.NewIpcServer(&cg.CenterServer{}) //client 初始化时和server通过chan建立通道 client := ipc.NewIpcClient(server) //centerClent 是IpcClient的sub,后续直接调用IpcClient的Call函数 centerClient = &cg.CenterClient{client} return nil } func Help(args []string) int { fmt.Println(` Commands: loginlogout send listplayer quit(q) help(h) `) return 0 } func Quit(args []string) int { return 1 } func Logout(args []string) int { if len(args) != 2 { fmt.Println("USAGE: logout ") return 0 } centerClient.RemovePlayer(args[1]) return 0 } func Login(args []string) int { if len(args) != 4 { fmt.Println("USAGE: login ") return 0 } level, err := strconv.Atoi(args[2]) if err != nil { fmt.Println("Invalid Parameter: should be an integer. ") return 0 } exp, err := strconv.Atoi(args[3]) if err != nil { fmt.Println("Invalid Parameter:should be an integer. ") return 0 } player := cg.NewPlayer() player.Name = args[1] player.Level = level player.Exp = exp //step comment:3 接收参数login tom 1 1生成player数据 err = centerClient.AddPlayer(player) if err != nil { fmt.Println("Failed adding player", err) } return 0 } func ListPlayer(args []string) int { ps, err := centerClient.ListPlayer("") if err != nil { fmt.Println("Failed. ", err) } else { for i, v := range ps { fmt.Println(i+1, ":", v) } } return 0 } func Send(args []string) int { message := strings.Join(args[1:], " ") err := centerClient.Broadcast(message) if err != nil { fmt.Println("Failed.", err) } return 0 } // 将命令和处理函数对应 func GetCommandHandlers() map[string]func(args []string) int { return map[string]func([]string) int{ "help": Help, "h": Help, "quit": Quit, "q": Quit, "login": Login, "logout": Logout, "listplayer": ListPlayer, "send": Send, } } func main() { fmt.Println("Casual Game Server Solution") startCenterService() Help(nil) r := bufio.NewReader(os.Stdin) handlers := GetCommandHandlers() for { // 循环读取用户输入 fmt.Print("Command> ") //step comment:2 例如login tom 1 1 b, _, _ := r.ReadLine() line := string(b) fmt.Println("line is:", line) tokens := strings.Split(line, " ") //tokens=[login tom 1 1] tokens[0]=login fmt.Println("tokens is: ", tokens) //login存在于handlers的key中,执行login对应的Login(login tom 1 1) if handler, ok := handlers[tokens[0]]; ok { ret := handler(tokens) if ret != 0 { break } } else { fmt.Println("Unknown command:", tokens[0]) } } }
2 centerclient.go
package cg import ( "encoding/json" "errors" "ipc" ) type CenterClient struct { *ipc.IpcClient } func (client *CenterClient) AddPlayer(player *Player) error { b, err := json.Marshal(*player) if err != nil { return err } //step comment:4 接收cgss中centerClient.AddPlayer(player),传参为player{login tom 1 1} //CenterClient为ipc.IpcClient的sub,直接调用ipc.IpcClient的Call方法 resp, err := client.Call("addplayer", string(b)) if err == nil && resp.Code == "200" { return nil } return err } func (client *CenterClient) RemovePlayer(name string) error { ret, _ := client.Call("removeplayer", name) if ret.Code == "200" { return nil } return errors.New(ret.Code) } func (client *CenterClient) ListPlayer(params string) (ps []*Player, err error) { resp, _ := client.Call("listplayer", params) if resp.Code != "200" { err = errors.New(resp.Code) return } err = json.Unmarshal([]byte(resp.Body), &ps) return } func (client *CenterClient) Broadcast(message string) error { m := &Message{Content: message} // 构造Message结构体 b, err := json.Marshal(m) if err != nil { return err } resp, _ := client.Call("broadcast", string(b)) if resp.Code == "200" { return nil } return errors.New(resp.Code) }
3 client.go
package ipc import ( "encoding/json" ) type IpcClient struct { conn chan string } func NewIpcClient(server *IpcServer) *IpcClient { c := server.Connect() //和IpcClient和IpcServer通过chan建立联系,此处的IpcServer其实是CenterServer return &IpcClient{c} } //step comment:5 centerClient.go 中调用client.Call("addplayer", string(b)) 接收参数addplayer和player{login tom 1 1} func (client *IpcClient) Call(method, params string) (resp *Response, err error) { req := &Request{method, params} var b []byte b, err = json.Marshal(req) if err != nil { return } //将player{login tom 1 1}传递给chan,即通过该chan向server传递消息,接收该消息的在server的Connnet的for中 client.conn <- string(b) str := <-client.conn // 等待返回值 var resp1 Response err = json.Unmarshal([]byte(str), &resp1) resp = &resp1 return } func (client *IpcClient) Close() { client.conn <- "CLOSE" }
4 server.go
package ipc import ( "encoding/json" "fmt" ) type Request struct { Method string "method" Params string "params" } type Response struct { Code string "code" Body string "body" } type Server interface { Name() string Handle(method, params string) *Response } type IpcServer struct { Server } func NewIpcServer(server Server) *IpcServer { return &IpcServer{server} } func (server *IpcServer) Connect() chan string { session := make(chan string, 0) go func(c chan string) { for { //step comment:6 fmt.Println("hand1") 会打印,hand2不打印,证明卡在这里,等待client传消息,但是Session依然会生成 /* Casual Game Server Solution A new session has been created successfully. Commands: login*/ request := <-c //fmt.Println("hand2") //不会打印 if request == "CLOSE" { // 关闭该连接 break } var req Request err := json.Unmarshal([]byte(request), &req) if err != nil { fmt.Println("Invalid request format:", request) } //调用center.go 中的处理函数server.addPlayer(params) //cgss初始化的时候server := ipc.NewIpcServer(&cg.CenterServer{}) //所以此处的server.Handle的调用方即初始化时的centerServer resp := server.Handle(req.Method, req.Params) b, err := json.Marshal(resp) c <- string(b) // 返回结果 } fmt.Println("Session closed.") }(session) fmt.Println("A new session has been created successfully.") return session } logout send listplayer quit(q) help(h) Command> hand1
5 center.go
1 package cg 2 3 import ( 4 "encoding/json" 5 "errors" 6 "ipc" 7 "sync" 8 ) 9 10 var _ ipc.Server = &CenterServer{} // 确认实现了Server接口 11 type Message struct { 12 From string "from" 13 To string "to" 14 Content string "content" 15 } 16 type CenterServer struct { 17 servers map[string]ipc.Server 18 players []*Player 19 //rooms []*Room 20 mutex sync.RWMutex 21 } 22 23 // 24 func NewCenterServer() *CenterServer { 25 servers := make(map[string]ipc.Server) 26 players := make([]*Player, 0) 27 return &CenterServer{servers: servers, players: players} 28 } 29 30 //step comment:8 login tom 1 1 31 func (server *CenterServer) addPlayer(params string) error { 32 player := NewPlayer() 33 err := json.Unmarshal([]byte(params), &player) 34 if err != nil { 35 return err 36 } 37 server.mutex.Lock() 38 defer server.mutex.Unlock() 39 // 偷懒了,没做重复登录检查 40 server.players = append(server.players, player) 41 return nil 42 } 43 func (server *CenterServer) removePlayer(params string) error { 44 server.mutex.Lock() 45 defer server.mutex.Unlock() 46 for i, v := range server.players { 47 if v.Name == params { 48 if len(server.players) == 1 { 49 server.players = make([]*Player, 0) 50 } else if i == len(server.players)-1 { 51 server.players = server.players[:i-1] 52 } else if i == 0 { 53 server.players = server.players[1:] 54 } else { 55 server.players = append(server.players[:i-1], server.players[:i+ 56 1]...) 57 } 58 return nil 59 } 60 } 61 return errors.New("Player not found.") 62 } 63 func (server *CenterServer) listPlayer(params string) (players string, err error) { 64 server.mutex.RLock() 65 defer server.mutex.RUnlock() 66 if len(server.players) > 0 { 67 b, _ := json.Marshal(server.players) 68 players = string(b) 69 } else { 70 err = errors.New("No player online.") 71 } 72 return 73 } 74 func (server *CenterServer) broadcast(params string) error { 75 var message Message 76 err := json.Unmarshal([]byte(params), &message) 77 if err != nil { 78 return err 79 } 80 server.mutex.Lock() 81 defer server.mutex.Unlock() 82 if len(server.players) > 0 { 83 for _, player := range server.players { 84 player.mq <- &message 85 } 86 } else { 87 err = errors.New("No player online.") 88 } 89 return err 90 } 91 92 //实现server接口Hanle方法 93 func (server *CenterServer) Handle(method, params string) *ipc.Response { 94 switch method { 95 //step comment:7 addplayer 和palyer {login tom 1 1} 96 case "addplayer": 97 err := server.addPlayer(params) 98 if err != nil { 99 return &ipc.Response{Code: err.Error()} 100 } 101 case "removeplayer": 102 err := server.removePlayer(params) 103 if err != nil { 104 return &ipc.Response{Code: err.Error()} 105 } 106 case "listplayer": 107 players, err := server.listPlayer(params) 108 if err != nil { 109 return &ipc.Response{Code: err.Error()} 110 } 111 return &ipc.Response{"200", players} 112 case "broadcast": 113 err := server.broadcast(params) 114 if err != nil { 115 return &ipc.Response{Code: err.Error()} 116 } 117 return &ipc.Response{Code: "200"} 118 default: 119 return &ipc.Response{Code: "404", Body: method + ":" + params} 120 } 121 return &ipc.Response{Code: "200"} 122 } 123 124 //实现server接口中Name方法 125 func (server *CenterServer) Name() string { 126 return "CenterServer" 127 }