分享
  1. 首页
  2. 文章

GO语言练习:channel 工程实例

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

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大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
6262 次点击
1 回复 | 直到 2025年05月13日 22:29:08
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏