golang rpc demo

RPC工作流程图

 

  • 1.调用客户端句柄;执行传送参数
  • 2.调用本地系统内核发送网络消息
  • 3.消息传送到远程主机
  • 4.服务器句柄得到消息并取得参数
  • 5.执行远程过程
  • 6.执行的过程将结果返回服务器句柄
  • 7.服务器句柄返回结果,调用远程系统内核
  • 8.消息传回本地主机
  • 9.客户句柄由内核接收消息
  • 10.客户接收句柄返回的数据

 

Go语言提供对RPC的支持:HTTP、TCP、JSPNRPC,但是在GoRPC是独一无二的,它采用了GoLang Gob编码,只能支持Go语言!

  • GoLang Gob:是Golang包自带的一个数据结构序列化的编码/解码工具。编码使用Encoder,解码使用Decoder。一种典型的应用场景就是RPC(remote procedure calls)。

HTTP RPC Demo

  • 服务端的代码
    package main
    
    import (
        "errors"
        "fmt"
        "net/http"
        "net/rpc"
    )
    
    type Arith int 
    
    func rpcDemo() {
        arith := new(Arith)
        fmt.Println("arith===", arith)
    
        rpc.Register(arith)
        //HandleHTTP将RPC消息的HTTP处理程序注册到Debug服务器
        //DEFAUTUPCPATH和Debug调试路径上的调试处理程序。
        //仍然需要调用http.Services(),通常是在GO语句中。
        rpc.HandleHTTP()
        err := http.ListenAndServe(":1234", nil)
        if err != nil {
            fmt.Println("err=====", err.Error())
        }   
    }
    
    type Args struct {
        A, B int
    }
    
    type Quotient struct {
        Quo, Rem int
    }
    
    //函数必须是导出的(首字母大写)
    //必须有两个导出类型的参数,
    //第一个参数是接收的参数,第二个参数是返回给客户端的参数,第二个参数必须是指针类型的
    //函数还要有一个返回值error
    func (t *Arith) Multiply(args *Args, reply *int) error {
        *reply = args.A * args.B
        fmt.Println("这个方法执行了啊---嘿嘿--- Multiply ", reply)
    
        return nil
    }
    
    func (t *Arith) Divide(args *Args, quo *Quotient) error {
        if args.B == 0 {
            return errors.New("divide by zero")
        }
    
        quo.Quo = args.A / args.B
        quo.Rem = args.A % args.B
        fmt.Println("这个方法执行了啊---嘿嘿--- Divide quo==", quo)
    
        return nil
    }
    
    func main() {
        rpcDemo()
    }

    服务端运行:go run server.go

  • 客户端的代码
    package main
    
    import (
        "flag"
        "fmt"
        "log"
        "net/rpc"
        "strconv"
    )
    
    type ArgsTwo struct {
        A, B int 
    }
    
    type QuotientTwo struct {
        Quo, Rem int 
    }
    
    type Conf struct {
        serverAddress string
        i1            string
        i2            string
    }
    
    var conf = Conf{}
    
    func SetConfiguration() {
        flag.StringVar(&conf.serverAddress, "address", "127.0.0.1:1234", "The address of the rpc")
        flag.StringVar(&conf.i1, "i1", "100", "100")
        flag.StringVar(&conf.i2, "i2", "2", "2")
    }
    
    func main() {
        SetConfiguration()
        flag.Parse()
        fmt.Println("severAddress = ", conf.serverAddress)
    
        // DelayHTTP在指定的网络地址连接到HTTP RPC服务器
        // 在默认HTTP RPC路径上监听。
        client, err := rpc.DialHTTP("tcp", conf.serverAddress)
        if err != nil {
            log.Fatal("发生错误了 在这里地方  DialHTTP", err)
        }
    
        i1_, _ := strconv.Atoi(conf.i1)
        i2_, _ := strconv.Atoi(conf.i2)
        args := ArgsTwo{A: i1_, B: i2_}
        var reply int
    
        //调用调用命名函数,等待它完成,并返回其错误状态。
        err = client.Call("Arith.Multiply", args, &reply)
        if err != nil {
            log.Fatal("Call Multiply  发生错误了哦   arith error:", err)
        }
        fmt.Printf("Arith 乘法: %d*%d=%d\n", args.A, args.B, reply)
    
        var quot QuotientTwo
        //调用调用命名函数,等待它完成,并返回其错误状态。
        err = client.Call("Arith.Divide", args, &quot)
        if err != nil {
            log.Fatal("arith error:", err)
        }
        fmt.Printf("Arith 除法取整数: %d/%d=%d 余数 %d\n", args.A, args.B, quot.Quo, quot.Rem)
    }

    客户端编译:go build client.go
    客户端运行:

  • [root@wangjq rpc]# ./client 
    severAddress =  127.0.0.1:1234
    Arith 乘法: 100*2=200
    Arith 除法取整数: 100/2=50 余数 0
    [root@wangjq rpc]# 
    [root@wangjq rpc]# ./client --address 127.0.0.1:1234 -i1 200 -i2 5
    severAddress =  127.0.0.1:1234
    Arith 乘法: 200*5=1000
    Arith 除法取整数: 200/5=40 余数 0

     

 

posted @ 2019-09-23 11:58  salami_china  阅读(544)  评论(0编辑  收藏  举报