美文网首页
89.go微服务之jsonRPC实践

89.go微服务之jsonRPC实践

作者: 厚土火焱 | 来源:发表于2021-03-21 23:38 被阅读0次

    go语言中的RPC只能在go语言的程序中调用。如果使用其他语言编写的客户端,就要用到jsonRPC了。jsonRPC可以被跨语言调用。
    这里我们采用一个计算乘法和除法求商取余数的例子来实践。
    首先,服务端server.go声明算术运算结构体和接收的参数结构体及返回客户端参数结构体。

    //  声明算术运算结构体
    type Arith struct {
    
    }
    
    //  声明接收的参数结构体
    type ArithRequest struct {
        A,B int
    }
    
    //  声明返回客户端参数结构体
    type ArithResponse struct {
        //  乘积
        Pro int
        //  商
        Quo int
        //  余数
        Rem int
    }
    

    计算乘法的函数

    //  乘法运算
    func (a *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
        res.Pro = req.A * req.B
        return nil
    }
    

    计算商和余数的时候,要注意一下需要考虑除数不能为0的情况。当除数为0的时候,就要用到返回结果error了。

    //  商和余数运算
    func (a *Arith) Divide(req ArithRequest, res *ArithResponse) error {
        if req.B == 0 {
            return errors.New("除数不能为0")
        }
        //  计算 商
        res.Quo = req.A / req.B
        //  计算 余数
        res.Rem = req.A % req.B
    
        return nil
    }
    

    在主函数中,首先要注册服务

        //  注册服务
        arith := new(Arith)
        rpc.Register(arith)
    

    然后要监听服务。这里我们采用tcp协议。需要确定服务采用的通讯端口,这里我们采用8081端口。

        //  监听服务
        lis, err := net.Listen("tcp", "127.0.0.1:8081")
        if err != nil {
            log.Fatal(err)
        }
    

    之后就是持续监听等待客户端访问,每当有访问发生就产生一个goroutine。如果一个客户端的连接发生错误,要忽略这次错误,进入下一个循环等待阶段。这里使用for循环实现。

        for true {
            conn, err := lis.Accept()
            if err != nil {
                continue
            }
    
            go func(conn net.Conn) {
                fmt.Println("new Client")
                jsonrpc.ServeConn(conn)
            }(conn)
        }
    

    也许你对携程(goroutine)这里的代码有些困惑。那么对比一下下面的代码。

    go xxx(conn)
    ...
    func xxx(conn net.Conn) {
                fmt.Println("new Client")
                jsonrpc.ServeConn(conn)
            }
    
    

    服务端的代码就是这些了。
    下面是客户端client.go的代码。
    首先声明一下接收参数和返回客户端参数的结构体。他们和服务端是完全一样的。

    //  声明接收的参数结构体
    type ArithRequest struct {
        A,B int
    }
    
    //  声明返回客户端参数结构体
    type ArithResponse struct {
        //  乘积
        Pro int
        //  商
        Quo int
        //  余数
        Rem int
    }
    

    在主函数中,远程连接rpc,连接的方式采用jsonrpc,按照tcp协议和服务端提供的地址和接口访问。

        //  连接远程rpc
        conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8081")
        if err != nil {
            log.Println(err)
        }
    

    声明要计算的参数和返回参数变量

        req := ArithRequest{9, 2}
        var res ArithResponse
    

    调用服务端函数,得到计算结果

        //  调用乘积
        err2 := conn.Call("Arith.Multiply", req, &res)
        if err2 != nil {
            log.Println(err2)
        }
        fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro)
        //  调用商
        err3 := conn.Call("Arith.Divide", req, &res)
        if err3 != nil {
            log.Println(err3)
        }
        fmt.Printf("%d / %d,商 = %d, 余数 = %d\n", req.A, req.B, res.Quo, res.Rem)
    
    

    运行结果:

    9 * 2 = 18
    9 / 2,商 = 4, 余数 = 1

    server端完整代码

    /**
    * Package: rpcServer2
    * Description: This package is ...
    * Author: Jian Junbo
    * Email: junbojian@qq.com
    * Date:  2021/3/21 20:48
    * Copyright ©2021 Jian Junbo & Shanxi Xiyue Mancang Technology Co., Ltd. All rights reserved.
    **/
    package main
    
    import (
        "errors"
        "fmt"
        "log"
        "net"
        "net/http"
        "net/rpc"
        "net/rpc/jsonrpc"
    )
    
    //  声明算术运算结构体
    type Arith struct {
    
    }
    
    //  声明接收的参数结构体
    type ArithRequest struct {
        A,B int
    }
    
    //  声明返回客户端参数结构体
    type ArithResponse struct {
        //  乘积
        Pro int
        //  商
        Quo int
        //  余数
        Rem int
    }
    
    //  乘法运算
    func (a *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
        res.Pro = req.A * req.B
        return nil
    }
    //  商和余数运算
    func (a *Arith) Divide(req ArithRequest, res *ArithResponse) error {
        if req.B == 0 {
            return errors.New("除数不能为0")
        }
        //  计算 商
        res.Quo = req.A / req.B
        //  计算 余数
        res.Rem = req.A % req.B
    
        return nil
    }
    
    func mainrpc() {
        //  注册服务
        arith := new(Arith)
        rpc.Register(arith)
        //  绑定http协议
        rpc.HandleHTTP()
    
        err := http.ListenAndServe(":8081", nil)
        if err != nil {
            log.Fatal(err)
        }
    }
    
    func main() {
        //  注册服务
        arith := new(Arith)
        rpc.Register(arith)
        //  监听服务
        lis, err := net.Listen("tcp", "127.0.0.1:8081")
        if err != nil {
            log.Fatal(err)
        }
    
        for true {
            conn, err := lis.Accept()
            if err != nil {
                continue
            }
    
            go func(conn net.Conn) {
                fmt.Println("new Client")
                jsonrpc.ServeConn(conn)
            }(conn)
        }
    }
    
    

    client端完整代码

    /**
    * Package: rpcClient2
    * Description: This package is ...
    * Author: Jian Junbo
    * Email: junbojian@qq.com
    * Date:  2021/3/21 20:57
    * Copyright ©2021 Jian Junbo & Shanxi Xiyue Mancang Technology Co., Ltd. All rights reserved.
    **/
    package main
    
    import (
        "fmt"
        "log"
        "net/rpc/jsonrpc"
    )
    
    //  声明接收的参数结构体
    type ArithRequest struct {
        A,B int
    }
    
    //  声明返回客户端参数结构体
    type ArithResponse struct {
        //  乘积
        Pro int
        //  商
        Quo int
        //  余数
        Rem int
    }
    
    func main() {
        //  连接远程rpc
        conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8081")
        if err != nil {
            log.Println(err)
        }
        req := ArithRequest{9, 2}
        var res ArithResponse
        //  调用乘积
        err2 := conn.Call("Arith.Multiply", req, &res)
        if err2 != nil {
            log.Println(err2)
        }
        fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro)
        //  调用商
        err3 := conn.Call("Arith.Divide", req, &res)
        if err3 != nil {
            log.Println(err3)
        }
        fmt.Printf("%d / %d,商 = %d, 余数 = %d\n", req.A, req.B, res.Quo, res.Rem)
    
    }
    
    

    相关文章

      网友评论

          本文标题:89.go微服务之jsonRPC实践

          本文链接:https://www.haomeiwen.com/subject/ghwocltx.html