在了解GRPC之前,先了解RPC:
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
简单来说,就是跟远程访问或者web请求差不多,都是一个client向远端服务器请求服务返回结果,但是web请求使用的网络协议是http高层协议,而rpc所使用的协议多为TCP,是网络层协议,减少了信息的包装,加快了处理速度。
golang本身有rpc包,可以方便的使用,来构建自己的rpc服务,下边是一个简单是实例,可以加深我们的理解:
1.调用客户端句柄;执行传送参数
2.调用本地系统内核发送网络消息
3.消息传送到远程主机
4.服务器句柄得到消息并取得参数
5.执行远程过程
6.执行的过程将结果返回服务器句柄
7.服务器句柄返回结果,调用远程系统内核
8.消息传回本地主机
9.客户句柄由内核接收消息
10.客户接收句柄返回的数据
注意:
方法是导出的
方法有两个参数,都是导出类型或内建类型
方法的第二个参数是指针
方法只有一个error接口类型的返回值
方法样式:
func (t *T) MethodName(argType T1, replyType *T2) error
package main
import (
"net/rpc"
"net"
"net/http"
"fmt"
)
type Panda struct {
}
func (this *Panda)GetAdd(In int ,Out *int)error{
*Out = In +10000
return nil
}
func main() {
//结构体实例化
pd :=new(Panda)
//注册服务
//Register在默认服务中注册并公布 接收服务 pd对象 的方法
rpc.Register(pd)
//rpc网络
rpc.HandleHTTP()
//建立网络监听
listener , err :=net.Listen("tcp","127.0.0.1:22306")
if err != nil{
fmt.Println("网络错误",err)
}
//等待网络连接
http.Serve(listener,nil)
}
package main
import (
"net/rpc"
"fmt"
)
func main() {
// 1连接服务器
cli ,err :=rpc.DialHTTP("tcp","127.0.0.1:22306")
if err!=nil{
fmt.Println("连接服务器失败",err)
return
}
// 2调用函数
//接受变量
var size int
//call(服务器的方法 , 传入参数 ,返回参数)
//Call(serviceMethod string, args interface{}, reply interface{})
err = cli.Call("Panda.GetAdd",12345 ,&size)
if err!=nil{
fmt.Println("方法调用失败",err)
return
}
// 3打印结果
fmt.Println("得到计算结果为",size)
}
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。
gRPC基于 HTTP/2标准设计,带来诸如双向流、流控、头部压缩、单 TCP连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
gRPC默认使用protoBuf
GRPC理念:
1.golang标准库的扩展包:
由于 go官网进不去,所以 我们需要的一些扩展包不能够 通过 go get 直接进行获取 ,可以通过go语言在github的地址 进行获取内容 https://github.com/golang
git clone 对应的内容地址 就可以
2.grpc包:
https://github.com/grpc/grpc-go
如果想要将消息类型用在RPC(远程方法调用)系统中,可以在.proto文件中定义一个RPC服务接口,protocol buffer编译器将会根据所选择的不同语言生成服务接口代码及存根。如,想要定义一个RPC服务并具有一个方法,该方法能够接收 SearchRequest并返回一个SearchResponse,此时可以在.proto文件中进行如下定义:
service SearchService {
//rpc 服务的函数名 (传入参数)返回(返回参数)
rpc Search (SearchRequest) returns (SearchResponse);
}
在当前文件下,编译 .proto文件
$ protoc --go_out=./ *.proto #不加grpc插件
$ protoc --go_out=plugins=grpc:./ *.proto #添加grpc插件
#对比发现内容增加
#得到 helloServer.pb.go文件
.proto文件
// 版本
syntax = "proto3" ;
//包名
package myproto ;
//服务
service Hello {
// 加法
rpc GetAdd(In)returns(Out); //不能写注释
}
//传入
message In{
//num
int64 num = 1 ; //不能写注释
}
//传出
message Out{
//size
int64 size =1 ;//不能写注释
}
服务端
package main
import (
"context"
pb "0609/grpc/myproto"
"net"
"fmt"
"google.golang.org/grpc"
)
//1 结构体
type Panda struct {
}
//2 结构体的方法
func (this *Panda ) GetAdd(ctx context.Context, in *pb.In) ( *pb.Out, error){
return &pb.Out{Size:10086+in.Num} ,nil
}
func main() {
// 3 创建网络
ln ,err :=net.Listen("tcp","127.0.0.1:12580")
if err!=nil{
fmt.Println("网络连接失败 ",err)
return
}
defer ln.Close()
// 4 创建grpc句柄
srv :=grpc.NewServer()
// 5 将grpc 句柄和 结构体注册
pb.RegisterHelloServer(srv ,&Panda{})
// 6 等待网络连接
err =srv.Serve(ln)
if err!=nil{
fmt.Println("连接失败 ",err)
return
}
}
客户端
package main
import (
"google.golang.org/grpc"
"fmt"
pb "0609/grpc/myproto"
"context"
)
func main() {
// 1 连接服务端
conn ,err :=grpc.Dial("127.0.0.1:12580",grpc.WithInsecure())
if err!=nil{
fmt.Println("网络连接失败 ",err)
return
}
defer conn.Close()
// 2 创建客户端句柄
cli :=pb.NewHelloClient(conn)
// 3 调用函数
out ,err :=cli.GetAdd(context.Background(),&pb.In{Num:12345})
if err!=nil{
fmt.Println("函数调用失败 ",err)
return
}
// 4打印结果
fmt.Println("计算结果为:",out.Size)
}