ipc server 代码分析

分析见注释

 1 cgss.go

package main

import (
    "bufio"
    "cg"
    "fmt"
    "ipc"
    "os"
    "strconv"
    "strings"
)

var centerClient *cg.CenterClient

func startCenterService() error {
    //step comment:1,CenterServer 实现了Server 接口,NewIpcServer也建立了和server.go中server.handler()建立
    server := ipc.NewIpcServer(&cg.CenterServer{})
    //client 初始化时和server通过chan建立通道
    client := ipc.NewIpcClient(server)
    //centerClent 是IpcClient的sub,后续直接调用IpcClient的Call函数
    centerClient = &cg.CenterClient{client}
    return nil
}
func Help(args []string) int {
    fmt.Println(`
 Commands:
 login <username><level><exp>
 logout <username>
 send <message>
 listplayer
 quit(q)
 help(h)
 `)
    return 0
}
func Quit(args []string) int {
    return 1
}
func Logout(args []string) int {
    if len(args) != 2 {
        fmt.Println("USAGE: logout <username>")
        return 0
    }
    centerClient.RemovePlayer(args[1])
    return 0
}
func Login(args []string) int {
    if len(args) != 4 {
        fmt.Println("USAGE: login <username><level><exp>")
        return 0
    }
    level, err := strconv.Atoi(args[2])
    if err != nil {
        fmt.Println("Invalid Parameter: <level> should be an integer.")
        return 0
    }
    exp, err := strconv.Atoi(args[3])
    if err != nil {
        fmt.Println("Invalid Parameter: <exp> should be an integer.")
        return 0
    }
    player := cg.NewPlayer()
    player.Name = args[1]
    player.Level = level
    player.Exp = exp
    //step comment:3 接收参数login tom 1 1生成player数据
    err = centerClient.AddPlayer(player)
    if err != nil {
        fmt.Println("Failed adding player", err)
    }
    return 0
}
func ListPlayer(args []string) int {
    ps, err := centerClient.ListPlayer("")
    if err != nil {
        fmt.Println("Failed. ", err)
    } else {
        for i, v := range ps {
            fmt.Println(i+1, ":", v)
        }
    }
    return 0
}
func Send(args []string) int {
    message := strings.Join(args[1:], " ")
    err := centerClient.Broadcast(message)
    if err != nil {
        fmt.Println("Failed.", err)
    }
    return 0
}

// 将命令和处理函数对应
func GetCommandHandlers() map[string]func(args []string) int {
    return map[string]func([]string) int{
        "help":       Help,
        "h":          Help,
        "quit":       Quit,
        "q":          Quit,
        "login":      Login,
        "logout":     Logout,
        "listplayer": ListPlayer,
        "send":       Send,
    }
}
func main() {
    fmt.Println("Casual Game Server Solution")
    startCenterService()
    Help(nil)
    r := bufio.NewReader(os.Stdin)
    handlers := GetCommandHandlers()
    for { // 循环读取用户输入
        fmt.Print("Command> ")
        //step comment:2 例如login tom 1 1
        b, _, _ := r.ReadLine()
        line := string(b)
        fmt.Println("line is:", line)
        tokens := strings.Split(line, " ")
        //tokens=[login tom 1 1] tokens[0]=login
        fmt.Println("tokens is: ", tokens)
        //login存在于handlers的key中,执行login对应的Login(login tom 1 1)
        if handler, ok := handlers[tokens[0]]; ok {
            ret := handler(tokens)
            if ret != 0 {
                break
            }
        } else {
            fmt.Println("Unknown command:", tokens[0])
        }
    }
}

2 centerclient.go

package cg

import (
    "encoding/json"
    "errors"

    "ipc"
)

type CenterClient struct {
    *ipc.IpcClient
}

func (client *CenterClient) AddPlayer(player *Player) error {
    b, err := json.Marshal(*player)
    if err != nil {
        return err
    }
    //step comment:4  接收cgss中centerClient.AddPlayer(player),传参为player{login tom 1 1}
    //CenterClient为ipc.IpcClient的sub,直接调用ipc.IpcClient的Call方法
    resp, err := client.Call("addplayer", string(b))
    if err == nil && resp.Code == "200" {
        return nil
    }
    return err
}
func (client *CenterClient) RemovePlayer(name string) error {
    ret, _ := client.Call("removeplayer", name)
    if ret.Code == "200" {
        return nil
    }
    return errors.New(ret.Code)
}
func (client *CenterClient) ListPlayer(params string) (ps []*Player, err error) {
    resp, _ := client.Call("listplayer", params)
    if resp.Code != "200" {
        err = errors.New(resp.Code)
        return
    }
    err = json.Unmarshal([]byte(resp.Body), &ps)
    return
}
func (client *CenterClient) Broadcast(message string) error {
    m := &Message{Content: message} // 构造Message结构体
    b, err := json.Marshal(m)
    if err != nil {
        return err
    }
    resp, _ := client.Call("broadcast", string(b))
    if resp.Code == "200" {
        return nil
    }
    return errors.New(resp.Code)
}

3 client.go

package ipc

import (
    "encoding/json"
)

type IpcClient struct {
    conn chan string
}

func NewIpcClient(server *IpcServer) *IpcClient {
    c := server.Connect()
    //和IpcClient和IpcServer通过chan建立联系,此处的IpcServer其实是CenterServer
    return &IpcClient{c}
}

//step comment:5 centerClient.go 中调用client.Call("addplayer", string(b))  接收参数addplayer和player{login tom 1 1}
func (client *IpcClient) Call(method, params string) (resp *Response, err error) {
    req := &Request{method, params}
    var b []byte
    b, err = json.Marshal(req)
    if err != nil {
        return
    }
    //将player{login tom 1 1}传递给chan,即通过该chan向server传递消息,接收该消息的在server的Connnet的for中
    client.conn <- string(b)
    str := <-client.conn // 等待返回值
    var resp1 Response
    err = json.Unmarshal([]byte(str), &resp1)
    resp = &resp1
    return
}
func (client *IpcClient) Close() {
    client.conn <- "CLOSE"
}

4 server.go

package ipc

import (
    "encoding/json"
    "fmt"
)

type Request struct {
    Method string "method"
    Params string "params"
}
type Response struct {
    Code string "code"
    Body string "body"
}
type Server interface {
    Name() string
    Handle(method, params string) *Response
}
type IpcServer struct {
    Server
}

func NewIpcServer(server Server) *IpcServer {
    return &IpcServer{server}
}
func (server *IpcServer) Connect() chan string {
    session := make(chan string, 0)
    go func(c chan string) {
        for {
            //step comment:6 fmt.Println("hand1") 会打印,hand2不打印,证明卡在这里,等待client传消息,但是Session依然会生成
            /*
               Casual Game Server Solution
               A new session has been created successfully.

                Commands:
                login <username><level><exp>
                logout <username>
                send <message>
                listplayer
                quit(q)
                help(h)

               Command> hand1

            */
            request := <-c
            //fmt.Println("hand2") //不会打印
            if request == "CLOSE" { // 关闭该连接
                break
            }
            var req Request
            err := json.Unmarshal([]byte(request), &req)
            if err != nil {
                fmt.Println("Invalid request format:", request)
            }
            //调用center.go 中的处理函数server.addPlayer(params)
            //cgss初始化的时候server := ipc.NewIpcServer(&cg.CenterServer{})
            //所以此处的server.Handle的调用方即初始化时的centerServer
            resp := server.Handle(req.Method, req.Params)
            b, err := json.Marshal(resp)
            c <- string(b) // 返回结果
        }
        fmt.Println("Session closed.")
    }(session)
    fmt.Println("A new session has been created successfully.")
    return session
}

5 center.go

  1 package cg
  2 
  3 import (
  4     "encoding/json"
  5     "errors"
  6     "ipc"
  7     "sync"
  8 )
  9 
 10 var _ ipc.Server = &CenterServer{} // 确认实现了Server接口
 11 type Message struct {
 12     From    string "from"
 13     To      string "to"
 14     Content string "content"
 15 }
 16 type CenterServer struct {
 17     servers map[string]ipc.Server
 18     players []*Player
 19     //rooms   []*Room
 20     mutex sync.RWMutex
 21 }
 22 
 23 //
 24 func NewCenterServer() *CenterServer {
 25     servers := make(map[string]ipc.Server)
 26     players := make([]*Player, 0)
 27     return &CenterServer{servers: servers, players: players}
 28 }
 29 
 30 //step comment:8 login tom 1 1
 31 func (server *CenterServer) addPlayer(params string) error {
 32     player := NewPlayer()
 33     err := json.Unmarshal([]byte(params), &player)
 34     if err != nil {
 35         return err
 36     }
 37     server.mutex.Lock()
 38     defer server.mutex.Unlock()
 39     // 偷懒了,没做重复登录检查
 40     server.players = append(server.players, player)
 41     return nil
 42 }
 43 func (server *CenterServer) removePlayer(params string) error {
 44     server.mutex.Lock()
 45     defer server.mutex.Unlock()
 46     for i, v := range server.players {
 47         if v.Name == params {
 48             if len(server.players) == 1 {
 49                 server.players = make([]*Player, 0)
 50             } else if i == len(server.players)-1 {
 51                 server.players = server.players[:i-1]
 52             } else if i == 0 {
 53                 server.players = server.players[1:]
 54             } else {
 55                 server.players = append(server.players[:i-1], server.players[:i+
 56                     1]...)
 57             }
 58             return nil
 59         }
 60     }
 61     return errors.New("Player not found.")
 62 }
 63 func (server *CenterServer) listPlayer(params string) (players string, err error) {
 64     server.mutex.RLock()
 65     defer server.mutex.RUnlock()
 66     if len(server.players) > 0 {
 67         b, _ := json.Marshal(server.players)
 68         players = string(b)
 69     } else {
 70         err = errors.New("No player online.")
 71     }
 72     return
 73 }
 74 func (server *CenterServer) broadcast(params string) error {
 75     var message Message
 76     err := json.Unmarshal([]byte(params), &message)
 77     if err != nil {
 78         return err
 79     }
 80     server.mutex.Lock()
 81     defer server.mutex.Unlock()
 82     if len(server.players) > 0 {
 83         for _, player := range server.players {
 84             player.mq <- &message
 85         }
 86     } else {
 87         err = errors.New("No player online.")
 88     }
 89     return err
 90 }
 91 
 92 //实现server接口Hanle方法
 93 func (server *CenterServer) Handle(method, params string) *ipc.Response {
 94     switch method {
 95     //step comment:7 addplayer 和palyer {login tom 1 1}
 96     case "addplayer":
 97         err := server.addPlayer(params)
 98         if err != nil {
 99             return &ipc.Response{Code: err.Error()}
100         }
101     case "removeplayer":
102         err := server.removePlayer(params)
103         if err != nil {
104             return &ipc.Response{Code: err.Error()}
105         }
106     case "listplayer":
107         players, err := server.listPlayer(params)
108         if err != nil {
109             return &ipc.Response{Code: err.Error()}
110         }
111         return &ipc.Response{"200", players}
112     case "broadcast":
113         err := server.broadcast(params)
114         if err != nil {
115             return &ipc.Response{Code: err.Error()}
116         }
117         return &ipc.Response{Code: "200"}
118     default:
119         return &ipc.Response{Code: "404", Body: method + ":" + params}
120     }
121     return &ipc.Response{Code: "200"}
122 }
123 
124 //实现server接口中Name方法
125 func (server *CenterServer) Name() string {
126     return "CenterServer"
127 }
原文地址:https://www.cnblogs.com/eiguleo/p/10432905.html