Go日记——反向RPC

Posted Guardians

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go日记——反向RPC相关的知识,希望对你有一定的参考价值。

背景


通常的RPC是基于C/S结构,RPC的服务端对应网络的服务器,RPC的客户端也对应网络客户端。但是对于一些特殊场景,比如在公司内网提供一个RPC服务,但是在外网无法链接到内网的服务器。这种时候我们可以参考类似反向代理的技术,首先从内网主动链接到外网的TCP服务器,然后基于TCP链接向外网提供RPC服务
声明接口
1|type HelloService struct {} 2|
3|func (p *HelloService) Hello(request string, reply *string) error {
4|    *reply = "hello:" + request
5|    return nil
6|}

反向RPC服务
1|func main() {
2|    rpc.Register(new(HelloService))
3|
4|    for {
5|        conn, _ := net.Dial("tcp", "localhost:1234")
6|        if conn == nil {
7|            time.Sleep(time.Second)
8|           continue
9|        }
10|
11|        rpc.ServeConn(conn)
12|        conn.Close()
13|    }
14|}
反向RPC的内网服务将不再主动提供TCP监听服务,而是首先主动链接到对方的TCP服务器。然后基于每个建立的TCP链接向对方提供RPC服务。

RPC客户端

RPC客户端则需要在一个公共的地址提供一个TCP服务,用于接受RPC服务器的链接请求:
1|func main() {
2|    listener, err := net.Listen("tcp", ":1234")
3|    if err != nil {
4|        log.Fatal("ListenTCP error:", err)
5|    }
6| 7|    clientChan := make(chan *rpc.Client)
8|
9|    go func() {
10|        for {
11|            conn, err := listener.Accept()
12|            if err != nil {
13|                log.Fatal("Accept error:", err)
14|            }
15|
16|            clientChan <- rpc.NewClient(conn)
17|        }
18|    }()
19|
20|    doClientWork(clientChan)
21|}
当每个链接建立后,基于网络链接构造RPC客户端对象并发送到clientChan管道。
客户端执行RPC调用的操作在doClientWork函数完成:
1|func doClientWork(clientChan <-chan *rpc.Client) {
2|    client := <-clientChan
3|    defer client.Close()
4|
5|    var reply string
6|    err = client.Call("HelloService.Hello", "hello", &reply)
7|    if err != nil {
8|        log.Fatal(err)
9|    }
10|
11|    fmt.Println(reply)
12|}
首先从管道去取一个RPC客户端对象,并且通过defer语句指定在函数退出前关闭客户端。然后是执行正常的RPC调用。


以上是关于Go日记——反向RPC的主要内容,如果未能解决你的问题,请参考以下文章

go开发日记001-环境搭建问题

我被Go反射折磨48小时后,反被我拿捏!!| 实习日记Go反射

kratos使用日记

python读书日记-20200626

创业日记薄Go出行:要借助SAAS系统帮助传统车企解决日常派单问题

Docker学习日记