Go语言操作grpc详细使用
- 零、参考链接
- 一、protobuf的详细使用
- 二、grpc与protobuf的go文件的生成
- 1.安装两个插件
- 2.写proto文件
- 3.编译proto文件,生成go文件
- 三、grpc的详细使用
- 1.一元RPC模式
- 2.客户端流RPC模式
- 3.服务器端流RPC模式
- 4.双向流RPC模式
零、参考链接
视频:90分钟搞懂分布式RPC开源框架
一、protobuf的详细使用
protobuf的单独使用
二、grpc与protobuf的go文件的生成
1.安装两个插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
2.写proto文件
syntax = "proto3";
option go_package = "../proto_go;protos";
message Person{
string name = 1;
int32 id = 2;
}
message IPhoneInfo {
string name = 1;
int32 id = 2;
string email = 3;
enum phoneType{
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message phoneNumber{
string number = 1;
phoneType type = 2;
}
phoneNumber phones = 4;
}
service ProdService{
rpc GetProdStock(Person) returns (IPhoneInfo);
}
3.编译proto文件,生成go文件
在pbfiles的文件目录下,运行下面的命令
protoc --go_out=../proto_go --go_opt=paths=source_relative --go-grpc_out=../proto_go --go-grpc_opt=paths=source_relative echo.proto
会在proto_go下生成两个文件
注意:每次修改了pbfiles中的.proto文件之后,都要重新编译生成两个文件
三、grpc的详细使用
可以直接看这个:gRPC开发: gRPC的四种通信模式
1.一元RPC模式
proto文件,最后的服务函数写这个,然后编译文件。
service ProdService{
rpc GetProdStock(Person) returns (IPhoneInfo);
}
客户端
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
protos "grpc/proto_go"
"log"
"time"
)
var person = []string{"cjs", "dh", "jay", "tom"}
func main() {
conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("Did not connect:%v", err)
}
defer conn.Close()
c := protos.NewProdServiceClient(conn)
for _, name := range person {
p := &protos.Person{
Name: name,
Id: 1,
}
ack, err := c.GetProdStock(context.Background(), p)
if err != nil {
panic(err)
}
fmt.Println(ack)
time.Sleep(time.Second)
}
var wg sync.WaitGroup
wg.Add(len(person))
for _, name := range person {
p := &protos.Person{
Name: name,
Id: 1,
}
go func(*protos.Person) {
ack, err := c.GetProdStock(context.Background(), p)
if err != nil {
panic(err)
}
fmt.Println(ack)
wg.Done()
}(p)
}
wg.Wait()
}
服务端
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
protos "grpc/proto_go"
"net"
)
type server struct {
protos.UnimplementedProdServiceServer
}
func (s *server) GetProdStock(ctx context.Context, req *protos.Person) (*protos.IPhoneInfo, error) {
name := req.GetName()
fmt.Println(name)
if info, ok := AddressBook[name]; ok {
return info, nil
}
return nil, status.Errorf(codes.NotFound, "Order does not exist.:", req.Name, req.Id)
}
var AddressBook map[string]*protos.IPhoneInfo
func main() {
DBAddressBook()
rpcs := grpc.NewServer()
protos.RegisterProdServiceServer(rpcs, &server{})
listen, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
defer listen.Close()
if err = rpcs.Serve(listen); err != nil {
panic(err)
}
}
func DBAddressBook() {
AddressBook = make(map[string]*protos.IPhoneInfo)
AddressBook["cjs"] = &protos.IPhoneInfo{
Name: "cjs",
Id: 1,
Email: "cjs_svip@163.com",
Phones: &protos.IPhoneInfoPhoneNumber{
Number: "18131371662",
Type: 1,
},
}
AddressBook["dh"] = &protos.IPhoneInfo{
Name: "dh",
Id: 2,
Email: "dh_svip@163.com",
Phones: &protos.IPhoneInfoPhoneNumber{
Number: "18131371663",
Type: 2,
},
}
AddressBook["jay"] = &protos.IPhoneInfo{
Name: "jay",
Id: 3,
Email: "jay_svip@163.com",
Phones: &protos.IPhoneInfoPhoneNumber{
Number: "18131371664",
Type: protos.IPhoneInfo_MOBILE,
},
}
AddressBook["tom"] = &protos.IPhoneInfo{
Name: "tom",
Id: 4,
Email: "tom_svip@163.com",
Phones: &protos.IPhoneInfoPhoneNumber{
Number: "18131371665",
Type: 1,
},
}
}
2.客户端流RPC模式
proto文件,最后的服务函数写这个,然后编译文件。
message AddressBook{
repeated IPhoneInfo people = 1;
}
service ProdService{
rpc GetProdStock(Person) returns (IPhoneInfo); //上一步中的,留着也没问题
rpc GetCStreamStock(stream Person) returns (AddressBook);
}
客户端
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
protos "grpc/proto_go"
"log"
)
var person = []string{"cjs", "dh", "jay", "tom"}
func main() {
conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("Did not connect:%v", err)
}
defer conn.Close()
c := protos.NewProdServiceClient(conn)
stream, err := c.GetCStreamStock(context.Background())
if err != nil {
panic(err)
}
for _, name := range person {
p := &protos.Person{
Name: name,
Id: 1,
}
err := stream.Send(p)
if err != nil {
panic(err)
}
}
recv, err := stream.CloseAndRecv()
if err != nil {
panic(err)
}
fmt.Println(recv)
}
服务端(把这个函数添加到上一步骤的服务端文件中即可)
func (s *server) GetCStreamStock(stream protos.ProdService_GetCStreamStockServer) error {
book := protos.AddressBook{People: make([]*protos.IPhoneInfo, 0)}
for {
recv, err := stream.Recv()
if err == io.EOF {
return stream.SendAndClose(&book)
}
name := recv.GetName()
fmt.Println(name)
if info, ok := AddressBook[name]; ok {
book.People = append(book.People, info)
}
}
}
3.服务器端流RPC模式
proto文件,最后的服务函数写这个,然后编译文件。
message SearchPerson{
repeated Person per = 1;
}
service ProdService{
rpc GetProdStock(Person) returns (IPhoneInfo); //上一步中的,留着也没问题
rpc GetCStreamStock(stream Person) returns (AddressBook); //上一步中的,留着也没问题
rpc GetSStreamStock(SearchPerson) returns (stream IPhoneInfo);
}
客户端
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
protos "grpc/proto_go"
"io"
"log"
)
var person = []string{"cjs", "dh", "jay", "tom"}
func main() {
conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("Did not connect:%v", err)
}
defer conn.Close()
c := protos.NewProdServiceClient(conn)
lists := make([]*protos.Person, 0)
for _, name := range person {
p := &protos.Person{
Name: name,
Id: 1,
}
lists = append(lists, p)
}
ackStream, err := c.GetSStreamStock(context.Background(), &protos.SearchPerson{Per: lists})
if err != nil {
panic(err)
}
for {
recv, err := ackStream.Recv()
if err != nil && err != io.EOF {
panic(err)
} else if err == io.EOF {
break
}
fmt.Println(recv)
}
}
服务端(把这个函数添加到上一步骤的服务端文件中即可)
func (s *server) GetSStreamStock(sp *protos.SearchPerson, stream protos.ProdService_GetSStreamStockServer) error {
for _, person := range sp.Per {
if info, ok := AddressBook[person.Name]; ok {
err := stream.Send(info)
if err != nil {
return fmt.Errorf("error sending message to stream:%v", err)
}
}
}
return nil
}
4.双向流RPC模式
proto文件,最后的服务函数写这个,然后编译文件。
service ProdService{
rpc GetProdStock(Person) returns (IPhoneInfo);//上一步中的,留着也没问题
rpc GetCStreamStock(stream Person) returns (AddressBook);//上一步中的,留着也没问题
rpc GetSStreamStock(SearchPerson) returns (stream IPhoneInfo);//上一步中的,留着也没问题
rpc GetCSStreamStock(stream Person) returns (stream IPhoneInfo);
}
客户端
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
protos "grpc/proto_go"
"io"
"log"
"sync"
"time"
)
var person = []string{"cjs", "dh", "jay", "tom"}
func main() {
conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("Did not connect:%v", err)
}
defer conn.Close()
c := protos.NewProdServiceClient(conn)
stream, err := c.GetCSStreamStock(context.Background())
if err != nil {
panic(err)
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
for {
recv, err := stream.Recv()
if err != nil && err != io.EOF {
panic(err)
} else if err == io.EOF {
wg.Done()
return
}
fmt.Println(recv)
}
}()
go func() {
for _, name := range person {
p := &protos.Person{
Name: name,
Id: 1,
}
err := stream.Send(p)
if err != nil {
panic(err)
}
time.Sleep(time.Second)
}
err := stream.CloseSend()
if err != nil {
panic(err)
}
}()
wg.Wait()
}
服务端(把这个函数添加到上一步骤的服务端文件中即可)
func (s *server) GetCSStreamStock(stream protos.ProdService_GetCSStreamStockServer) error {
for {
recv, err := stream.Recv()
if err != nil && err != io.EOF {
panic(err)
} else if err == io.EOF {
return nil
}
if info, ok := AddressBook[recv.Name]; ok {
fmt.Println(recv.Name)
err := stream.Send(info)
if err != nil {
panic(err)
}
}
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)