grpc初探

什么是rpc

RPC(Remote Procedure Call,远程过程调用)是一种计算机编程模型和协议,允许一个程序在另一个地址空间(通常是远程计算机上)执行函数或过程调用,就像调用本地函数一样。RPC 的目标是使分布式系统中的不同组件能够相互通信和协作,而不必手动编写复杂的网络通信代码。(chatGPT解释)

是什么grpc

gRPC(gRPC Remote Procedure Call)是一种高性能、跨语言的远程过程调用(RPC)框架,由Google开发并开源。它建立在HTTP/2协议上,使用Protocol Buffers(protobuf)作为接口定义语言(IDL),支持多种编程语言。gRPC的目标是使分布式系统之间的通信更加高效、可靠和易于扩展。(chatGPT解释)

protoc文件简要了解

1
2
3
4
5
6
7
syntax="proto3"; //指定版本号

message SearchReqeust {
string KeyWord=1;

}

image-20231004144526377

image-20231004151742178

Hello world Demo

编写 proto文件

Server端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
syntax = "proto3";

option go_package ="server/pb";// 项目中import 导入生成的Go代码的名称

package pb; // proto文件模块

service Greeter{
rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest{
string name =1;
}

message HelloResponse{
string reply=1;
}

Client 端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
syntax = "proto3";

option go_package ="client/pb";

package pb;

service Greeter{
rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest{
string name =1;
}

message HelloResponse{
string reply=1;
}

执行 proto文件

1
2
3
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
pb/hello.proto
1
2
3
protoc --proto_path=pb --go_out=pb --go_opt=paths=source_relative \
--go-grpc_out=pb --go-grpc_opt=paths=source_relative \
hello.proto
1
2
3
protoc -I=pb --go_out=pb --go_opt=paths=source_relative \
--go-grpc_out=pb --go-grpc_opt=paths=source_relative \
hello.proto
1
2
3
4
--I=pb 指定protoc_path 
--go_out 指定pb.go输出文件位置
--go-grpc_out 指定grpc代码的位置

编写 逻辑代码

Server端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"context"
"log"
"microService_Learning/grpc_demo/server/pb"
"net"

"google.golang.org/grpc"
)

// hello server

type server struct {
pb.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, request *pb.HelloRequest) (*pb.HelloResponse, error) {
return &pb.HelloResponse{Reply: "Hello" + request.Name}, nil
}

func main() {
listener, err := net.Listen("tcp", ":9091")
if err != nil {
log.Fatalf("net.Listen failed,err:%v\n", err)
return
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
if err = s.Serve(listener); err != nil {
log.Fatalf("s.Serve failed,err:%v\n", err)
}
}

Client端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//server/main.go
package main

import (
"context"
"flag"
"log"
"microService_Learning/grpc_demo/server/pb"
"time"

"google.golang.org/grpc/credentials/insecure"

"google.golang.org/grpc"
)

// hello_client

const (
defaultName = "world"
)

var (
// 注意 flag.String 返回的是 *string
addr = flag.String("addr", "127.0.0.1:9092", "the address to connect to")
name = flag.String("name", defaultName, "Name to greet")
)

func main() {
flag.Parse()
// 连接到server端,此处禁用安全传输
//conn, err := grpc.Dial(*addr, grpc.WithInsecure())
conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("grpc.Dail failed,err:%v\n", err)
return
}
defer conn.Close()

//执行rpc调用 并打印返回相应的值
client := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*3)
defer cancel()
r, err := client.SayHello(ctx, &pb.HelloRequest{Name: *name})
if err != nil {
log.Fatalf("counld not greet :%v\n", err)
return
}
log.Printf("Greeting :,%s", r.GetReply())
}

Add Demo

server端 proto 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//path: add_server/pb/add.proto
syntax="proto3";

package add_sever;

option go_package ="add_server/pb";

service Add{
rpc CalcService(AddRequest) returns (AddResponse);
}

message AddRequest{
int64 x=1;
int64 y=2;
}

message AddResponse{
int64 res=1;
}

server端具体逻辑代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// path: add_server/main.go
package main

import (
"add_server/pb"
"context"
"log"

"net"

"google.golang.org/grpc"
)

type server struct {
pb.UnimplementedAddServer
}

func (s *server) CalcService(ctx context.Context, in *pb.AddRequest) (*pb.AddResponse, error) {
sum := int64(in.GetX()) + int64(in.GetY())
return &pb.AddResponse{Res: sum}, nil
}

func main() {
listener, err := net.Listen("tcp", ":3000")
if err != nil {
log.Fatalf("net.Listen failed,err:%v", err)
return
}
s := grpc.NewServer()
pb.RegisterAddServer(s, &server{})
if err = s.Serve(listener); err != nil {
log.Fatalf("s.Serve failed,err:%v", err)
}
}

client端 proto 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// path: add_client/pb/add.proto
syntax="proto3";

package add_sever;

option go_package ="add_client/pb";

service Add{
rpc CalcService(AddRequest) returns (AddResponse);
}

message AddRequest{
int64 x=1;
int64 y=2;
}

message AddResponse{
int64 res=1;
}

client端具体逻辑代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// path: add_client/main.go
package main

import (
"add_client/pb"
"context"
"flag"
"log"
"time"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

var (
x = flag.Int("x", 10, "x的值")
y = flag.Int("y", 110, "x的值")
)

func main() {
flag.Parse()
//建立连接
conn, err := grpc.Dial("127.0.0.1:3000", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("grpc.Dial failed,err:%v", err)
return
}
defer conn.Close()

//创建 rpc client端
client := pb.NewAddClient(conn)
ctx, cacel := context.WithTimeout(context.Background(), time.Second)
defer cacel()
resp, err := client.CalcService(ctx, &pb.AddRequest{
X: int64(*x),
Y: int64(*y),
})
if err != nil {
log.Fatalf("client.CalcService failed,err:%v", err)
return
}
log.Printf("res:%v", resp.GetRes())
}

参考


grpc初探
http://example.com/2023/09/11/grpc初探/
作者
Forrest
发布于
2023年9月11日
许可协议