GO语言练习:channel 工程实例

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

时间: 2024-08-12 18:03:35

GO语言练习:channel 工程实例的相关文章

在windows下用C语言写socket通讯实例

原文:在windows下用C语言写socket通讯实例 From:Microsoft Dev Center #undef UNICODE #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <stdlib.h> #include <stdio.h> // Need to link with Ws2

Cisco3550配置作为DHCP服务器工程实例

C3550配置作为DHCP服务器工程实例 网络环境: 一台3550EMI交换机,划分三个vlan,vlan2 为服务器所在网络,命名为server,IP地址段为192.168.2.0,子网掩码:255.255.255.0,网关:192.168.2.1,域服务器为windows2000 advance server, 同时兼作DNS服务器,IP地址为192.168.2.10,vlan3为客户机1所在网络,IP地址段为192.168.3.0, 子网掩码:255.255.255.0,网关:192.16

程序设计语言具有心理工程及技术

程序设计语言具有心理工程及技术等特性. (1)心理特性:歧义性.简洁性.局部性.顺序性.传统性. (2)工程特性:可移植性,开发工具的可利用性,软件的可重用性.可维护性. (3)技术特性:支持结构化构造的语言有利于减少程序环路的复杂性,使程序易测试.易维护. 1 package Com.TableTest; 2 3 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 import java.io.IOExc

C语言数组和函数实例练习

C语言的数组和函数部分的知识,在语法上和Java语法是有所相似的,这里只通过实例总结一些自己感觉需要理解的部分知识. 1.数组 数组中的元素具有相同的数据类型:数组一旦创建,不能被改变:数组中元素在内存中是连续依次存在的:使用时需要随时注意下标越界的问题. 例1:输入数量不确定的[0,9]范围内的整数,统计每个数字出现的次数,输入-1时结束程序. #include <stdio.h> #include <stdlib.h> int main() { int i; int num[1

Go语言学习——channel的死锁其实没那么复杂

1 为什么会有信道 协程(goroutine)算是Go的一大新特性,也正是这个大杀器让Go为很多路人驻足欣赏,让信徒们为之欢呼津津乐道. 协程的使用也很简单,在Go中使用关键字“go“后面跟上要执行的函数即表示新启动一个协程中执行功能代码. func main() { go test() fmt.Println("it is the main goroutine") time.Sleep(time.Second * 1) } func test() { fmt.Println(&quo

Redis教程(十五):C语言连接操作代码实例

转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/143.html 在之前的博客中已经非常详细的介绍了Redis的各种操作命令.运行机制和服务器初始化参数配置.本篇博客是该系列博客中的最后一篇,在这里将给出基于Redis客户端组件访问并操作Redis服务器的代码示例.然而需要说明的是,由于Redis官方并未提供基于C接口的Windows平台客户端,因此下面的示例仅可运行于Linux/Unix平台.但是对于使用其它编程语言的

C语言接口与实现实例

一个模块有两部分组成:接口和实现.接口指明模块要做什么,它声明了使用该模块的代码可用的标识符.类型和例程,实现指明模块是如何完成其接口声明的目标的,一个给定的模块通常只有一个接口,但是可能会有许多种实现能够提供接口所指定的功能.每个实现可能使用不同的算法和数据结构,但是它们都必须符合接口所给出的使用说明.客户调用程序是使用某个模块的一段代码,客户调用程序导入接口,而实现导出接口.由于多个客户调用程序是共享接口和实现的,因此使用实现的目标代码避免了不必要的代码重复,同时也有助于避免错误,因为接口和

在mvc4中多语言建站的实例

环境:vs2012 asp.net mvc4. 实现方式:resource 资源文件,根据路由规则中Lang参数来判断载入哪种语言方式 在网上找到了相关资料,顺便自己做了个练习,新建工程之类的步骤就免了,该注意的地方说明下,记着方便下次使用. 1:添加资源文件,记得设置资源文件的访问模式为public,不然默认是Internal,外面会访问不到: 2:添加路由规则,记得加在Default路由规则的前面,否则新规则没用,详细原因请参考这篇文章 1 routes.Add(new Route( 2 "

[日常] Go语言圣经--Channel习题

练习 8.3: 在netcat3例子中,conn虽然是一个interface类型的值,但是其底层真实类型是*net.TCPConn,代表一个TCP连接.一个TCP连接有读和写两个部分,可以使用CloseRead和CloseWrite方法分别关闭它们.修改netcat3的主goroutine代码,只关闭网络连接中写的部分,这样的话后台goroutine可以在标准输入被关闭后继续打印从reverb1服务器传回的数据.(要在reverb2服务器也完成同样的功能是比较困难的:参考练习 8.4.) 1.n