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

你可能感兴趣的:(channel)