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

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

内容简介:做项目中发现自己对很多东西的理解有偏差,所以决定做个总结,也分享给需要的朋友。如有错误和遗漏,欢迎沟通交流。本文介绍了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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Discrete Mathematics and Its Applications

Discrete Mathematics and Its Applications

Kenneth H Rosen / McGraw-Hill Science/Engineering/Math / 2003-04-22 / USD 132.81

Discrete Mathematics and its Applications is a focused introduction to the primary themes in a discrete mathematics course, as introduced through extensive applications, expansive discussion, and deta......一起来看看 《Discrete Mathematics and Its Applications》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具