zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    spring applicationContext.xml中<beans>中属性概述
    ES6新特性
    JavaWeb工程 目录结构
    web项目目录结构
    关于 eclipse启动卡死的问题 解决方法
    eclipse 僵死/假死 问题排查及解决
    Ajax的text/plain、application/x-www-form-urlencoded和application/json
    js的等值比较规则
    jsp页面中注释 <!-- --> 和<%-- --%> 的区别
    Spring的配置文件ApplicationContext.xml配置头文件解析
  • 原文地址:https://www.cnblogs.com/eiguleo/p/10432905.html
Copyright © 2011-2022 走看看