文章目录
grpc使用
要想知道grpc,先了解rpc(文章中这些都是我自己,学习中的小笔记不详细。想详细了解请百度,有很多资料。)
什么是rpc?
定义:
远程过程调用协议和http请求类似,只不过协议不同,rpc使用的大多数为TCP,http请求使用的为HTTP协议。
可以简单的理解为一个节点调用另外一个节点。
组成:
- 客户端:Client,服务调用方。
- 客户端存根:Client Stub,存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端
- 网络传输模块:Network Service,底层传输,可以是TC 或HTTP
- 服务端存根:Server Stub,接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
- 服务端等:server服务的真正提供者。
执行过程:
- Client 客户端通过本地调用的方式调用服务。
- 客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体。
- 客户端存根(Client Stub)找到远程的服务地址,并且将消息通过网络发送给服务端。
- 网络传输
- 服务端存根(Server Stub)收到消息后进行解码(反序列化操作)。
- 服务端存根(Server Stub)根据解码结果调用本地的服务进行相关处理
- 服务端(Server)本地服务业务处理。
- 处理结果返回给服务端存根(Server Stub)。
- 服务端存根(Server Stub)序列化结果。
- 服务端存根(Server Stub)将结果通过网络发送至消费方。
- 客户端存根(Client Stub)接收到消息,并进行解码(反序列化)。
- 客户端得到最终结果。
什么是grpc
定义:
- 是一个高性能、开源、通用的RPC框架。
- gRPC中采用的是HTTP2协议
- 谷歌的产品
- gRPC默认使用protoBuf
组成:类似rpc
执行过程:类似rpc
注意:
rpc和grpc详细了解,请百度搜索
文章中如有错误,请联系我.
go实现rpc
服务端:
rpc_sample/go_rpc_server.go
package main
import (
"fmt"
"net"
"net/http"
"net/rpc"
)
type Say struct{
}
/*
注意:对外暴露的服务方法定义
1、对外暴露的方法有且只能有两个参数,这两个参数只能是输出类型或内建类型,两种类型中的一种。
2、方法的第二个参数必须是指针类型。
3、方法的返回类型为error。
*/
func (s *Say) Hello(inputArg string, outputArg *string) error {
*outputArg = "hello " + inputArg
return nil
}
func main() {
// new一个对象
say := new(Say)
// 将对象注册到rpc服务中
rpc.Register(say)
// 把say中的服务注册到HTTP协议上,方便调用者可以利用http的方式进行数据传递
rpc.HandleHTTP()
listen, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Printf("net.Listen failed ,%v\n", err)
return
}
http.Serve(listen, nil)
}
运行:go run go_rpc_server.go
客户端:
rpc_sample/go_rpc_client.go
package main
import (
"fmt"
"net/rpc"
)
func main() {
// DialHTTP:使用http去拨号,与服务端创建连接
client, err := rpc.DialHTTP("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Printf("rpc.DialHTTP failed ,%v\n", err)
return
}
// 返回值
var say string
/*
远程调用函数:被调用的方法,传入值 ,返回值
*/
err = client.Call("Say.Hello", "world!", &say)
if err != nil {
fmt.Printf("client.Call failed ,%v\n", err)
return
}
fmt.Println("结果为:", say)
}
/*
结果为: hello world!
*/
go run go_rpc_client.go
grpc使用
grpc安装
GO111MODULE=on
GOPROXY=https://goproxy.io,direct
# 设置GO111MODULE、GOPROXY下载无压力
go get google.golang.org/[email protected]
go get google.golang.org/genproto
proto内容定义
grpc_sample/grpc_protoBuf_sample/say_hi_sample.proto
syntax = "proto3";
option go_package = ".;hello";
package hello;
// 上面跟rpc基本一样定义
/*
grpc + protobuf
定义一个service类型
SayHi暴露函数名
可以定义多个服务,每个服务内可以定义多个接口
*/
service TestService {
// 定义接口 (结构体可以复用)
// 方法 (请求消息结构体) returns (返回消息结构体) {}
//rpc 服务端对外的函数名(传入参数)returns(返回参数)
rpc SayHi (HiRequest) returns (HiResponse){}
}
// 定义HiRequest消息结构
message HiRequest {
string name = 1;
}
// 定义HiResponse消息结构
message HiResponse {
string ret = 1;
}
proto生成go语言文件(grpc)
注意:grpc使用grpc插件
# 直接到say_hi_sample.proto文件目录执行
protoc --go_out=plugins=grpc:. say_hi_sample.proto
# 会生成say_hi_sample.pb.go文件
grpc服务端(server)
grpc_sample/go_grpc_server.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"net"
hello "sample/grpc_sample/grpc_protoBuf_sample"
)
type Server struct{
} //服务对象
/*
SayHi实现在proto中定义的TestServiceServer interface接口
type TestServiceServer interface {
//rpc 服务端对外的函数名(传入参数)returns(返回参数)
SayHi(context.Context, *HiRequest) (*HiResponse, error)
}
TestServiceServer接口是如何来的?
1.grpc_sample/grpc_protoBuf_sample/say_hi_sample.proto
proto文件中定义service类型的名为:TestService
2.proto转成go文件就会生成2个接口:
生成规律也很明显,就是proto文件中定义service类型的名后面加Client、Server
TestServiceClient
TestServiceServer
看名称很明显肯定关于客户端、服务端
*/
func (s *Server) SayHi(ctx context.Context, in *hello.HiRequest) (*hello.HiResponse, error) {
res := &hello.HiResponse{
Ret: "hello " + in.Name}
return res, nil
}
// name --> "hello name"
func main() {
// 创建grpc服务
server := grpc.NewServer()
/*
**注册接口服务:
* 以定义proto时的service为单位注册,服务中可以有多个方法
* (proto编译时会为每个service生成Register***Server方法)
* 包.注册服务方法(gRpc服务实例,包含接口方法的结构体[指针])
hello.RegisterTestServiceServer
grpc注册服务:
1.hello是包名
2.RegisterTestServiceServer注册服务一个方法
RegisterTestServiceServer:
1.参数一:grpc服务
2.参数二:服务对象
*/
hello.RegisterTestServiceServer(server, &Server{
})
listen, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Printf("监听失败: %v\n", err)
}
fmt.Println("监听8080端口...")
// 用grpc服务启动
server.Serve(listen)
}
运行:go run go_grpc_server.go
grpc客户端(client)
grpc_sample/go_grpc_client.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
hello "sample/grpc_sample/grpc_protoBuf_sample"
)
func main() {
/*
**建立连接到gRPC服务:
* WithInsecure:跳过证书的验证
*/
conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
if err != nil {
fmt.Printf("grpc.Dial failed, :%v\n", err)
}
// 结束时关闭连接
defer conn.Close()
// 创建TestService服务的客户端
client := hello.NewTestServiceClient(conn)
// 调用gRPC接口
rep, err1 := client.SayHi(context.Background(), &hello.HiRequest{
Name: "world!"})
if err1 != nil {
fmt.Printf("client.SayHi failed, :%v\n", err1)
return
}
fmt.Println(rep.Ret)
}
/* 运行结果:
hello wrold!
*/
运行:go run go_grpc_client.go
注意:
开启go module
用GoLand创建项目会有个go.mod,没有go mod init。详细go mod自行百度
grpc演示中hello "sample/grpc_sample/grpc_protoBuf_sample"
我这个go.mod中module sample是sample,引入同项目不同目录下包就是sample/...
后面使用micro会使用go module导入不同项目下包。前面先了解下,大神可以略过。
再次说明:这些都是我自己学习过程中小笔记,如有错误望告知。还有就是一些相关介绍少,想详细了解请自行百度。