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 mainView Code
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 cgView Code
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 cgView Code
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 cgView Code
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 ipcView Code
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 ipcView Code
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 ipcView Code
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语言编程》一书的第四章,目录结构及代码与原书有差异