GO语言练习:channel 工程实例

fengbohello · · 4315 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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 }
View Code

  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 }
View Code

    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 }
View Code

    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 }
View Code

  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 }
View Code

    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 }
View Code

    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 }
View Code

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

本文来自:博客园

感谢作者:fengbohello

查看原文:GO语言练习:channel 工程实例

入群交流(和以上内容无关):Go中文网 QQ 交流群:798786647 或加微信入微信群:274768166 备注:入群;关注公众号:Go语言中文网

4315 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传