不得不懂系列(2)-玩转Go中的RPC

栏目: 服务器 · 发布时间: 5年前

内容简介:做项目中发现自己对很多东西的理解有偏差,所以决定做个总结,也分享给需要的朋友。如有错误和遗漏,欢迎沟通交流。本文介绍了Go中原生和第三方RPC使用方法,环境搭建方法并提供了材料。

做项目中发现自己对很多东西的理解有偏差,所以决定做个总结,也分享给需要的朋友。如有错误和遗漏,欢迎沟通交流。

GitHub示例源码

本文介绍了 Go 中原生和第三方RPC使用方法,环境搭建方法并提供了材料。

RPC

远程过程调用(Remote Procedure Call),通俗的说,RPC可以实现跨机器、跨语言调用其他计算机的程序。举个例子,我在机器A上用 C语言 封装了某个功能的函数,我可以通过RPC在机器B上用GO语言调用机器A上的指定函数。 RPC为C/S模型,通常使用TCP或http协议。

Golang官方RPC

go RPC可以利用tcp或http来传递数据,可以对要传递的数据使用多种类型的编解码方式。

net/rpc库

Golang官方的net/rpc库可以通过tcp或http传递数据,但net/rpc库使用encoding/gob进行编解码,支持tcp或http数据传输方式,由于其他语言不支持gob编解码方式,所以使用net/rpc库实现的RPC方法没办法进行跨语言调用。

server端代码

package main

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

type Chen struct {
}

//rcp方法
//func (t *T) MethodName(argType T1, replyType *T2) error
func (this *Chen) GetAdd(data int, sum *int) error {

	*sum = data + 100

	return nil
}

func main() {
	//1.对象实例化
	pd := new(Chen)
	//2. rpc注册
	rpc.Register(pd)
	//3. rpc网络
	rpc.HandleHTTP()
	//4. 监听网络
	ln, err := net.Listen("tcp", "127.0.0.1:12306")
	if err != nil {
		fmt.Println("net.Listen error:", err)
		return
	}
	//5. 等待连接
	http.Serve(ln, nil)
}
复制代码

client代码

package main

import (
	"net/rpc"
	"fmt"
)

func main() {
	//1. 连接服务器
	cln, err := rpc.DialHTTP("tcp", "127.0.0.1:12306")
	if err != nil {
		fmt.Println("rpc.Dial error:", err)
		return
	}
	defer cln.Close()

	//2. 调用服务器函数
	var data int
	err = cln.Call("Chen.GetAdd",10, &data)
	if err != nil {
		fmt.Println("cln.Call error:", err)
		return
	}
	//3. 打印输出
	fmt.Println("计算结果为:", data)
}
复制代码

运行结果

客户端输出: 计算结果为: 110

net/rpc/jsonrpc库

Go官方还提供了使用json编解码的rpc库:net/rpc/jsonrpc,但是使用tcp传递数据,不能用http。

server代码

package main

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

type Chen struct {
}

//rcp方法
//func (t *T) MethodName(argType T1, replyType *T2) error
func (this *Chen) GetAdd(data int, sum *int) error {

	*sum = data + 100

	return nil
}

func main() {
	//1.对象实例化
	pd := new(Chen)
	//2. rpc注册
	rpc.Register(pd)

	//3. 监听网络
	ln, err := net.Listen("tcp", "127.0.0.1:12306")
	if err != nil {
		fmt.Println("net.Listen error:", err)
		return
	}

	//4. 处理客户端请求
	for {
		conn, err := ln.Accept()
		if err != nil {
			fmt.Println("Accept error:", err)
			continue
		}

		go func(conn net.Conn) {
			jsonrpc.ServeConn(conn)
		}(conn)
	}
}
复制代码

client代码

package main

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

func main() {
	//1. 连接服务器
	cln, err := jsonrpc.Dial("tcp", "127.0.0.1:12306")
	if err != nil {
		fmt.Println("jsonrpc.Dial error:", err)
		return
	}
	defer cln.Close()

	//2. 调用服务器函数
	var data int
	err = cln.Call("Chen.GetAdd",10, &data)
	if err != nil {
		fmt.Println("cln.Call error:", err)
		return
	}
	//3. 打印输出
	fmt.Println("计算结果为:", data)
}
复制代码

运行结果

客户端输出: 计算结果为: 110

gRPC

所以为了真正实现跨主机、跨语言的远程调用,需要使用第三方的RPC库,推荐使用谷歌开源的gRPC。gRPC基于HTTP/2,采用protobuf进行数据编解码,压缩和传输效率更高。可以参考本人的 Go语言protobuf入门 了解Go语言protobuf的环境搭建和使用。

gRPC安装

由于不能直接访问golang官网,所以安装gPRC和go扩展包比较麻烦,可以从本人 gRPC环境包安装 中获取压缩包。

unzip x.zip -d /GOPATH/src/golang.org/x
unzip google.golang.org.zip -d /GOPATH/src/google.golang.org
复制代码

gRPC环境测试

启动服务器端,

$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_server
$ go run main.go
复制代码

启动客户端,

$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_client
$ go run main.go
复制代码

如果客户端打印出 2019/06/10 15:26:12 Greeting: Hello world 字样即表示gRPC环境正常。

建立proto文件

//版本
syntax = "proto3";

//包名
package myproto;

//服务
service Hello {
    //这儿注释才有效
    rpc GetAdd(In)returns(Out);//这儿注释无效
}

//传入
message In {
    //此处1不是赋值,而是指参数序号
    int64 num = 1;
}

//传出
message Out {
    //此处1不是赋值,而是指参数序号
    int64 size = 1;
}
复制代码

生成go代码

在.proto文件所在目录执行下面的指令,

protoc --go_out=plugins=grpc:./ *.proto
复制代码

生成go代码时要指定plugins=grpc表示生成的是gRPC代码。

服务端代码

package main

import (
	"fmt"
	pb "gRPC/myproto" //给package起别名
	"context"
	"net"
	"google.golang.org/grpc"
)

//1. 结构体
type Chen struct {

}

//2. 该结构体实现HelloServer interface的方法
func (this *Chen)GetAdd(ctx context.Context, In *pb.In)(*pb.Out,error)  {
	return &pb.Out{Size:In.Num+100},nil
}

func main() {
	fmt.Println("server runing...")

	//3. 创建网络
	ln, err := net.Listen("tcp", "127.0.0.1:12345")
	if err != nil {
		fmt.Println("net.Listen error:", err)
		return
	}
	defer ln.Close()

	//4. 创建gRPC句柄
	srv := grpc.NewServer()

	//5. 注册server
	pb.RegisterHelloServer(srv, &Chen{})

	//6. 等待网络连接
	err = srv.Serve(ln)
	if err != nil {
		fmt.Println("srv.Serve error:", err)
		return
	}

}
复制代码

客户端代码

package main

import (
	"fmt"
	pb "gRPC/myproto" //给package起别名
	"context"
	"net"
	"google.golang.org/grpc"
)

//1. 结构体
type Chen struct {

}

//2. 该结构体实现HelloServer interface的方法
func (this *Chen)GetAdd(ctx context.Context, In *pb.In)(*pb.Out,error)  {
	return &pb.Out{Size:In.Num+100},nil
}

func main() {
	fmt.Println("server runing...")

	//3. 创建网络
	ln, err := net.Listen("tcp", "127.0.0.1:12345")
	if err != nil {
		fmt.Println("net.Listen error:", err)
		return
	}
	defer ln.Close()

	//4. 创建gRPC句柄
	srv := grpc.NewServer()

	//5. 注册server
	pb.RegisterHelloServer(srv, &Chen{})

	//6. 等待网络连接
	err = srv.Serve(ln)
	if err != nil {
		fmt.Println("srv.Serve error:", err)
		return
	}

}
复制代码

运行测试

先后运行服务器和客户端代码,可在客户端打印输出 得到数据: 110 ,说明已经成功在客户端调用服务端程序。


以上所述就是小编给大家介绍的《不得不懂系列(2)-玩转Go中的RPC》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

程序员的数学2

程序员的数学2

平冈和幸、堀玄 / 陈筱烟 / 人民邮电出版社 / 2015-8-1 / CNY 79.00

本书沿袭《程序员的数学》平易近人的风格,用通俗的语言和具体的图表深入讲解程序员必须掌握的各类概率统计知识,例证丰富,讲解明晰,且提供了大量扩展内容,引导读者进一步深入学习。 本书涉及随机变量、贝叶斯公式、离散值和连续值的概率分布、协方差矩阵、多元正态分布、估计与检验理论、伪随机数以及概率论的各类应用,适合程序设计人员与数学爱好者阅读,也可作为高中或大学非数学专业学生的概率论入门读物。一起来看看 《程序员的数学2》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具