1、工程代码
2、编译及运行
1、工程目录结构
$ tree cgss
cgss
├── cgss.go
└── src
├── cg
│ ├── centerclient.go
│ ├── center.go
│ └── player.go
└── ipc
├── client.go
├── ipc_test.go
└── server.go
1.1)主文件cgss.go 文件代码
1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "os" 7 "strconv" 8 "strings" 9 10 "cg" 11 "ipc" 12 ) 13 14 var centerClient * cg.CenterClient 15 16 func startCenterService() error { 17 server := ipc.NewIpcServer(&cg.CenterServer{}) 18 client := ipc.NewIpcClient(server) 19 centerClient = &cg.CenterClient{client} 20 21 return nil 22 } 23 24 func Help(args []string) int { 25 fmt.Println(` 26 Commands: 27 login <userbane><level><exp> 28 logout <username> 29 send <message> 30 listplayer 31 quit(q) 32 help(h) 33 `) 34 return 0 35 } 36 37 func Quit(args []string) int { 38 return 1 39 } 40 41 func Logout(args []string) int { 42 if len (args) != 2 { 43 fmt.Println("USAGE: logout <username>") 44 return 0 45 } 46 centerClient.RemovePlayer(args[1]) 47 48 return 0 49 } 50 51 func Login(args []string) int { 52 if len(args) != 4 { 53 fmt.Println("USAGE: login <username><level><exp>") 54 return 0 55 } 56 57 level, err := strconv.Atoi(args[2]) 58 if err != nil { 59 fmt.Println("Invaild Parameter : <level> should be an integer.") 60 return 0 61 } 62 exp, err := strconv.Atoi(args[3]) 63 if err != nil { 64 fmt.Println("Invaild Parameter : <exp> should be an integer.") 65 return 0 66 } 67 player := cg.NewPlayer() 68 player.Name = args[1] 69 player.Level = level 70 player.Exp = exp 71 72 err = centerClient.AddPlayer(player) 73 if err != nil { 74 fmt.Println("Faild adding player", err) 75 } 76 77 return 0 78 } 79 80 func ListPlayer(args []string) int { 81 ps , err := centerClient.ListPlayer("") 82 if err != nil { 83 fmt.Println("Faild. ", err) 84 } else { 85 for i, v := range ps { 86 fmt.Println(i + 1, ":", v) 87 } 88 } 89 return 0 90 } 91 92 func Send(args []string) int { 93 message := strings.Join(args[1:], " ") 94 95 err := centerClient.Broadcast(message) 96 if err != nil { 97 fmt.Println("Faild. ", err) 98 } 99 100 return 0 101 } 102 103 func GetCommandHandlers() map[string] func(args[]string) int { 104 return map[string]func([]string) int { 105 "help" : Help, 106 "h" : Help, 107 "quit" : Quit, 108 "q" : Quit, 109 "login" : Login, 110 "logout": Logout, 111 "listplayer": ListPlayer, 112 "send" : Send, 113 } 114 } 115 116 func main() { 117 fmt.Println("Casual Game Server Soluion") 118 119 startCenterService() 120 121 Help(nil) 122 123 r := bufio.NewReader(os.Stdin) 124 125 handlers := GetCommandHandlers() 126 127 for { 128 fmt.Print("command> ") 129 b, _, _ := r.ReadLine() 130 line := string(b) 131 132 tokens := strings.Split(line, " ") 133 134 if handler, ok := handlers[tokens[0]]; ok { 135 ret := handler(tokens) 136 if ret != 0 { 137 break 138 } 139 } else { 140 fmt.Println("Unknown command : ", tokens[0]) 141 } 142 } 143 }
1.2)cg 包的代码
1.2.1src/cg/centerclient.go
1 package cg 2 3 import ( 4 "errors" 5 "encoding/json" 6 7 "ipc" 8 ) 9 10 type CenterClient struct { 11 *ipc.IpcClient 12 } 13 14 func (client * CenterClient)AddPlayer(player * Player)error { 15 b, err := json.Marshal(*player) 16 if err != nil { 17 return err 18 } 19 20 resp, err := client.Call("addplayer", string(b)) 21 if err == nil && resp.Code == "200" { 22 return nil 23 } 24 25 return err 26 } 27 28 func (client *CenterClient)RemovePlayer(name string) error { 29 ret, _ := client.Call("removeplayer", name) 30 if ret.Code == "200" { 31 return nil 32 } 33 34 return errors.New(ret.Code) 35 } 36 37 func (client * CenterClient)ListPlayer(params string)(ps []*Player, err error) { 38 resp, _ := client.Call("listplayer", params) 39 if resp.Code != "200" { 40 err = errors.New(resp.Code) 41 return 42 } 43 44 err = json.Unmarshal([]byte(resp.Body), &ps) 45 return 46 } 47 48 func (client * CenterClient)Broadcast(message string) error { 49 m := &Message{Content:message} 50 51 b, err := json.Marshal(m) 52 if err != nil { 53 return err 54 } 55 resp, _ := client.Call("broadcast", string(b)) 56 if resp.Code == "200" { 57 return nil 58 } 59 60 return errors.New(resp.Code) 61 }
1.2.2)src/cg/center.go
1 package cg 2 3 import ( 4 "encoding/json" 5 "errors" 6 "sync" 7 8 "ipc" 9 ) 10 11 var _ ipc.Server = &CenterServer{} 12 13 type Message struct { 14 From string "from" 15 To string "to" 16 Content string "content" 17 } 18 19 type Room struct { 20 } 21 22 type CenterServer struct { 23 servers map[string] ipc.Server 24 players []*Player 25 rooms []*Room 26 mutex sync.RWMutex 27 } 28 29 func NewCenterServer() * CenterServer { 30 servers := make(map[string] ipc.Server) 31 players := make([]*Player, 0) 32 return &CenterServer{servers:servers, players:players} 33 } 34 35 func (server * CenterServer)addPlayer(params string) error { 36 player := NewPlayer() 37 38 err := json.Unmarshal([]byte(params), &player) 39 if err != nil { 40 return err 41 } 42 43 server.mutex.Lock() 44 defer server.mutex.Unlock() 45 46 server.players = append(server.players, player) 47 48 return nil 49 } 50 51 func (server * CenterServer)removePlayer(params string) error { 52 server.mutex.Lock() 53 defer server.mutex.Unlock() 54 55 for i, v := range server.players { 56 if v.Name == params { 57 if len(server.players) == 1 { 58 server.players = make([]*Player, 0) 59 } else if i == len(server.players) - 1 { 60 server.players = server.players[:i - 1] 61 } else if i == 0 { 62 server.players = server.players[1:] 63 } else { 64 server.players = append(server.players[:i - 1], server.players[:i + 1]...) 65 } 66 return nil 67 } 68 } 69 70 return errors.New("Player not found") 71 } 72 73 func (server * CenterServer)listPlayer(params string)(players string , err error) { 74 server.mutex.RLock() 75 defer server.mutex.RUnlock() 76 77 if len(server.players) > 0 { 78 b, _ := json.Marshal(server.players) 79 players = string(b) 80 } else { 81 err = errors.New("No play online.") 82 } 83 84 return 85 } 86 87 func (server * CenterServer)broadCast(params string) error { 88 var message Message 89 err := json.Unmarshal([]byte(params), &message) 90 if err != nil { 91 return err 92 } 93 94 server.mutex.Lock() 95 defer server.mutex.Unlock() 96 97 if len(server.players) > 0 { 98 for _, player := range server.players { 99 player.mq <- &message 100 } 101 } else { 102 err = errors.New("No player online.") 103 } 104 105 return err 106 } 107 108 func (server * CenterServer)Handle(method, params string) *ipc.Response { 109 switch method { 110 case "addplayer" : 111 err := server.addPlayer(params) 112 if err != nil { 113 return &ipc.Response{Code:err.Error()} 114 } 115 case "removeplayer" : 116 err := server.removePlayer(params) 117 if err != nil { 118 return &ipc.Response{Code:err.Error()} 119 } 120 case "listplayer" : 121 players, err := server.listPlayer(params) 122 if err != nil { 123 return &ipc.Response{Code:err.Error()} 124 } 125 return &ipc.Response{"200", players} 126 case "broadcast" : 127 err := server.broadCast(params) 128 if err != nil { 129 return &ipc.Response{Code:err.Error()} 130 } 131 return &ipc.Response{Code:"200"} 132 default : 133 return &ipc.Response{Code:"404", Body:method + ":" + params} 134 } 135 return &ipc.Response{Code:"200"} 136 } 137 138 func (server * CenterServer)Name() string { 139 return "CenterServer" 140 }
1.2.3)src/cg/player.go
1 package cg 2 3 import ( 4 "fmt" 5 ) 6 7 type Player struct { 8 Name string "name" 9 Level int "level" 10 Exp int "exp" 11 Room int "room" 12 13 mq chan * Message 14 } 15 16 func NewPlayer() * Player { 17 m := make(chan * Message, 1024) 18 player := &Player{"", 0, 0, 0, m} 19 20 go func (p * Player) { 21 for { 22 msg := <-p.mq 23 fmt.Println(p.Name, "received message :", msg.Content) 24 } 25 }(player) 26 27 return player 28 }
1.3)ipc 包的代码
1.3.1)src/ipc/client.go
1 package ipc 2 3 import ( 4 "encoding/json" 5 ) 6 7 type IpcClient struct { 8 conn chan string 9 } 10 11 func NewIpcClient(server * IpcServer) * IpcClient { 12 c := server.Connect() 13 14 return &IpcClient{c} 15 } 16 17 func (client * IpcClient)Call(method, params string) (resp * Response, err error) { 18 req := &Request{method, params} 19 20 var b []byte 21 b, err = json.Marshal(req) 22 if err != nil { 23 return 24 } 25 26 client.conn <- string(b) 27 28 str := <-client.conn 29 30 var resp1 Response 31 err = json.Unmarshal([]byte(str), &resp1) 32 resp = &resp1 33 34 return 35 } 36 37 func (client * IpcClient)Clsoe() { 38 client.conn <- "CLOSE" 39 }
1.3.2)src/ipc/ipc_test.go
1 package ipc 2 3 import ( 4 "testing" 5 ) 6 7 type EchoServer struct { 8 } 9 10 func (server * EchoServer) Handle(request string) string { 11 return "ECHO:" + request 12 } 13 14 func (server * EchoServer) Name() string { 15 return "EchoServer" 16 } 17 18 func TestIpc (t * testing.T) { 19 server := NewIpcServer(&EchoServer{}) 20 21 client1 := NewIpcClient(server) 22 client2 := NewIpcClient(server) 23 24 resq1 := client1.Call("From client1") 25 resq2 := client1.Call("From client2") 26 27 if resp1 != "ECHO:From client1" || resp2 != "ECHO:From client2" { 28 t.Error("IpcClient.Call faild. resp1:", resp1, "resp2:", resp2) 29 } 30 client1.Close() 31 client2.Close() 32 }
1.3.3)src/ipc/server.go
1 package ipc 2 3 import ( 4 "encoding/json" 5 "fmt" 6 ) 7 8 type Request struct { 9 Method string "method" 10 Params string "params" 11 } 12 13 type Response struct { 14 Code string "code" 15 Body string "body" 16 } 17 18 type Server interface { 19 Name() string 20 Handle(method, params string) *Response 21 } 22 23 type IpcServer struct { 24 Server 25 } 26 27 func NewIpcServer(server Server) * IpcServer { 28 return &IpcServer{server} 29 } 30 31 func (server * IpcServer)Connect() chan string { 32 session := make(chan string, 0) 33 34 go func(c chan string) { 35 for{ 36 request := <-c 37 if request == "CLOSE" { 38 break 39 } 40 var req Request 41 err := json.Unmarshal([]byte(request), &req) 42 if err != nil { 43 fmt.Println("Invalid request format:", request) 44 } 45 resp := server.Handle(req.Method, req.Params) 46 47 b, err := json.Marshal(resp) 48 c <- string(b) 49 } 50 fmt.Println("Session closed.") 51 }(session) 52 53 fmt.Println("A new session has been created successfully.") 54 55 return session 56 }
2、编译及运行
2.1)编译
export GOPATH="/home/fengbo/cgss" $ pwd /home/fengbo/cgss $ tree . ├── cgss.go └── src ├── cg │ ├── centerclient.go │ ├── center.go │ └── player.go └── ipc ├── client.go ├── ipc_test.go └── server.go $ go build $ tree . ├── cgss ├── cgss.go └── src ├── cg │ ├── centerclient.go │ ├── center.go │ └── player.go └── ipc ├── client.go ├── ipc_test.go └── server.go
2.2)运行
$ ./cgss Casual Game Server Soluion A new session has been created successfully. Commands: login <userbane><level><exp> logout <username> send <message> listplayer quit(q) help(h) command> login a 1 101 command> login b 2 202 command> listplayer 1 : &{a 1 101 0 <nil>} 2 : &{b 2 202 0 <nil>} command> send Hello boy a received message : Hello boy b received message : Hello boy command> logout a command> listplayer 1 : &{b 2 202 0 <nil>} command> logout b command> listplayer Faild. No play online. command> q
来源:《Go语言编程》一书的第四章,目录结构及代码与原书有差异