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

  • 相关阅读:
    练字的感悟
    关于简单
    全都是泡沫
    跟着电影环游世界
    12.8《印度之行》
    11.21派生类对基类的访问
    Linux,begin
    如何利用google
    回调函数
    原型对象
  • 原文地址:https://www.cnblogs.com/fengbohello/p/4660024.html
Copyright © 2020-2023  润新知