grpc服务端
首先安装环境,这里以mac os系统为例
Protoc安装
brew install protobuf
Protoc-gen-go的安装,然后在终端执行下方命令
go install github.com/golang/protobuf/protoc-gen-go@latest
安装grpc插件
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
编写proto代码
先定义一个hello.proto文件
syntax = "proto3";
option go_package = "./;proto";
package pb;
// 定义输入消息结构体
message HelloRequest {
string name = 1;
}
// 定义输出消息结构体
message HelloResponse {
string message = 1;
}
/*
定义服务接口(注意这里service后面的名字HelloService要跟下面service端里面的结构体的名字一样)
否者客户端调用的时候就会报错:rpc error: code = Unimplemented desc = unknown method SayHello for service pb.HelloService
*/
service HelloService {
rpc SayHello(HelloRequest) returns (HelloResponse);
}
开始写grpc服务端
-
服务端代码
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"log"
"net"
pb "test-logus/demo15-grpc/server/pb"
)
/*
这个结构体的名字要跟proto文件中定义服务接口的service名字相同,
否者客户端调用就会出现报错:rpc error: code = Unimplemented desc = unknown method SayHello for service pb.HelloService
*/
type HelloService struct {
pb.UnimplementedHelloServiceServer
}
// 这就是所谓的远程函数
func (s *HelloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
return &pb.HelloResponse{Message: "Hello " + in.Name}, nil
}
// 示例的验证函数
func validateRequest(ctx context.Context) bool {
// 在这里执行你的验证逻辑
// 返回 true 表示验证通过,返回 false 表示验证失败
return true
}
// 添加一个自定义的拦截器函数
func myInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
fmt.Println("拦截器:请求已经到达,正在处理...")
// 进行验证,如果验证不通过,返回错误
if !validateRequest(ctx) {
return nil, status.Errorf(codes.PermissionDenied, "权限验证失败")
}
// 在请求处理之前的操作
resp, err := handler(ctx, req)
// 在请求处理之后的操作
fmt.Println("拦截器:请求处理完成")
return resp, err
}
func main() {
aa := true
if aa {
// 创建带有TLS证书的gRPC服务器
//creds := credentials.NewTLS(tlsConfig)
creds, errs := credentials.NewServerTLSFromFile("demo15-grpc/server/ling.evilangel.vip.cer", "demo15-grpc/server/ling.evilangel.vip.key")
if errs != nil {
log.Fatalf("Failed to setup TLS: %v", errs)
}
// 创建监听器
lis, err := net.Listen("tcp", ":8972")
if err != nil {
fmt.Printf("监听本地端口失败: %v\n", err)
return
}
s := grpc.NewServer(grpc.Creds(creds), grpc.UnaryInterceptor(myInterceptor))
// 在gRPC服务端注册服务
pb.RegisterHelloServiceServer(s, &HelloService{})
fmt.Println("gRPC服务启动成功!!!")
// 启动服务
errss := s.Serve(lis)
if errss != nil {
fmt.Printf("启动服务失败: %v", errss)
return
}
} else {
//监听本地端口8972
lis, err := net.Listen("tcp", ":8972")
if err != nil {
fmt.Printf("监听本地端口失败: %v\n", err)
return
}
//创建grpc服务
s := grpc.NewServer(grpc.UnaryInterceptor(myInterceptor))
//在gRpc服务端注册服务
pb.RegisterHelloServiceServer(s, &HelloService{})
fmt.Println("grpc服务启动成功!!!")
//启动服务
errs := s.Serve(lis)
if errs != nil {
fmt.Printf("启动服务失败: %v", errs)
return
}
}
}
用下面的命令生成代码,这样生成就有grpc.pb.go文件了
- 注意最后面跟的如果是proto文件名的话·那么此时你要进入这个文件所在的终端,才能执行下面这个命令
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello.proto
编译启动
go build
./service
编写client端
把上面生成的proto文件拷贝一份给客户端文件夹下的pb文件夹下面
-
grpc客户端代码
package main
import (
"context"
"crypto/tls"
"flag"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
pb "test-logus/demo15-grpc/client/pb"
"time"
)
const (
defaultName = "world"
)
var (
addr = flag.String("addr", "127.0.0.1:8972", "the address to connect to")
name = flag.String("name", defaultName, "this is service name")
)
func main() {
flag.Parse()
// 忽略证书验证(仅用于开发和测试,不建议在生产环境使用)
creds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
// 连接到 gRPC 服务器
conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(creds))
if err != nil {
fmt.Printf("连接到 gRPC 服务器失败:%v\n", err)
return
}
defer func(conn *grpc.ClientConn) {
err := conn.Close()
if err != nil {
// 如果需要,在连接关闭时处理错误
}
}(conn)
// 创建 gRPC 客户端
client := pb.NewHelloServiceClient(conn)
go func() {
// 调用服务方法
for {
_, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "John"})
if err != nil {
fmt.Printf("调用服务方法失败:%v\n", err)
return
}
fmt.Println("心跳成功:")
time.Sleep(15 * time.Second)
}
}()
for {
// 调用服务方法
reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "John"})
if err != nil {
fmt.Printf("调用服务方法失败:%v\n", err)
return
}
fmt.Println("服务器回复:", reply.Message)
time.Sleep(180 * time.Second)
}
}
编译执行
go build
./client -name="梅梅"
最后看下服务端和客户端的截图
-
服务端截图
-
客户端截图