LOADING

MiniKano的小窝


 

【Go】微服务基础-使用Go实现简单的RPC服务

原理就是通过TCP等协议进行远程方法调用(Remote Procedure Call Protocol)

RPC有一个好处就是可以跨语言调用
java写的client/server也可以调用go中编写并暴露在网络中的RPC服务
不过下面的例子使用的协议是go专有的,如果想实现跨语言调用,需要统一协议(比如JSON RPC

下面是简单的代码实现

~ps:莫名想起了发布订阅模式~

Server端

// 原生实现的rpc Server
package main

import (
    "fmt"
    "net"
    "net/rpc"
)

// 定义一个远程调用的方法
type Hello struct {
    Name string
}

// 方法必须有两个参数,第二个需要是指针类型(毕竟需要操作修改)
// req 和res 不能和是Chanel或者func类型
func (Hello) SayHello(req string, res *string) error {
    fmt.Println("接收到数据:", req)
    *res = "好的好的,我是服务端,给你数据~"
    return nil
}
func main() {
    //注册一个rpc服务
    err1 := rpc.RegisterName("hello", Hello{Name: "hello方法"})
    if err1 != nil {
        fmt.Println("hello注册失败")
        return
    }
    Listrner, errNet := net.Listen("tcp", "localhost:8080")
    if errNet != nil {
        fmt.Println(errNet)
        return
    }

    //应用推出的时候关闭监听端口
    defer Listrner.Close()
    fmt.Println("开始建立链接:localhost:8080")

    for {
        //建立一次链接
        conn, errCon := Listrner.Accept()
        if errCon != nil {
            fmt.Println(errCon)
            return
        }

        //绑定服务
        rpc.ServeConn(conn)
    }
}

Client端

//原生实现的rpc Client

package main

import (
    "fmt"
    "net/rpc"
)

func main() {
    //通rpc连接服务器
    conn, err1 := rpc.Dial("tcp", "localhost:8080")
    if err1 != nil {
        fmt.Println(err1)
        return
    }
    //关闭时退出连接
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("出错咯")
        }
        conn.Close()
    }()
    //调用远程函数
    var reply string
    //调用订阅的结构体里的方法((
    err2 := conn.Call("hello.SayHello", "我是客户端,我来找你要数据了", &reply)
    if err2 != nil {
        fmt.Println(err2)
        return
    }
    //获取微服务返回的数据
    fmt.Println(reply)
}

上面演示了如何使用RPC进行远程调用方法并获取方法的操作结果

RPC方法中的reqres参数是类型可以是string struct等类型,但不能是func或者channel还有complex类型

演示使用struct类型作为函数参数

服务端方法

....
type Goods struct {
}

type AddGoodsReq struct {
    Id      int
    Title   string
    Price   float32
    Content string
}

type AddGoodsRes struct {
    Success bool
    Message string
}

func (Goods) Add(req AddGoodsReq, res *AddGoodsRes) error {
    //执行
    fmt.Println(req)
    *res = AddGoodsRes{
        Success: true,
        Message: "增加数据成功",
    }
    return nil
}
....

客户端

....
//客户端也需要提前声明请求体和返回提的类型
....
    //调用远程函数
    var reply AddGoodsRes
//调用订阅的结构体里的方法((
    req := AddGoodsReq{
        Id:      1,
        Title:   "test",
        Price:   3.14,
        Content: "this is a test DEMO for RPC",
    }
    err2 := conn.Call("goods.Add", req, &reply)
....

PS: 如果想使用JSON RPC ,只需要进行以下更改:
client端:

//建立基于JSON RPC编解码的RPC服务
    // conn, err1 := rpc.Dial("tcp", "localhost:8081")
    //使用了 jsonrpc.Dial 来建立 JSON-RPC 的连接,无需手动配置codec
    conn, err1 := jsonrpc.Dial("tcp", "localhost:8081")

server端:

// rpc.ServeConn(conn)

        //创建JSONRPC(过时写法)
        // rpc.ServeCodec(jsonrpc.NewServerCodec(conn))

        //jsonrpc里直接有ServeConn的实现
        jsonrpc.ServeConn(conn)
点赞
  1. ccbbp说道:
    IP属地: 中国–浙江–杭州 电信
    Google Chrome Windows 10

    据说php程序员最方便的转型是Go,我好奇Go是啥样的

发表回复

电子邮件地址不会被公开。必填项已用 * 标注