GRPC介绍

GRPC介绍

在这里插入图片描述

gRPC(gRPC Remote Procedure Call)是一种高性能、开源的远程过程调用(RPC)框架,由Google开发并开源发布。它基于HTTP/2协议进行通信,使用Protocol Buffers(通常简称为ProtoBuf)作为接口定义语言(IDL),可以用于构建分布式系统,允许不同的应用程序在不同的编程语言之间进行通信。

以下是一些关键的特点和概念,以帮助您更好地了解 gRPC:

  1. IDL (Interface Definition Language): gRPC使用 Protocol Buffers 作为接口定义语言,它是一种轻量级、高效的二进制序列化格式,用于定义服务接口和消息格式。ProtoBuf允许您定义数据结构和服务方法,然后生成多种编程语言的客户端和服务器代码。

  2. 多语言支持:gRPC支持多种编程语言,包括C++, Java, Python, Go, Ruby, C#, Node.js等,这意味着您可以在不同的语言中编写客户端和服务器代码,它们仍然可以相互通信。

  3. HTTP/2协议:gRPC基于HTTP/2,这是一种二进制协议,具有更好的性能和低延迟。HTTP/2支持多路复用、头部压缩、双向流等特性,这有助于提高效率和性能。

  4. 双向流:gRPC支持双向流,允许客户端和服务器之间的双向通信。这对于实时通信和流式数据非常有用。

  5. 自动代码生成:根据您的服务定义文件,gRPC可以自动生成客户端和服务器的代码,从而降低了开发的工作量。

  6. 拦截器:您可以添加拦截器来处理请求和响应,以执行认证、日志记录、错误处理等操作。

  7. 流控制:gRPC支持流式传输,这意味着可以处理大量数据或持续流的场景。

  8. 安全性:gRPC支持传输层安全性(TLS/SSL)和自定义认证,确保通信的安全性。

  9. 跨平台:由于支持多种编程语言,gRPC适用于各种平台,包括移动设备、嵌入式系统和服务器。

gRPC广泛应用于微服务架构中,以便不同的微服务之间可以轻松地通信,但它也可以用于其他分布式系统中。总之,gRPC提供了一种高效、跨语言、跨平台的通信方式,使开发者能够构建可扩展的分布式应用程序。


一、grpc四种数据流

gRPC支持四种不同类型的数据流,这些数据流类型可以用于定义客户端和服务器之间的通信方式。这四种数据流类型分别是:

  1. 单一请求,单一响应(Unary RPC)

    • 在这种模式下,客户端向服务器发送一个请求,然后等待服务器响应。
    • 这是最常见的 RPC 模式,类似于传统的函数调用。
    • 用于需要点对点通信、请求-响应模式的场景。
  2. 单一请求,流式响应(Server Streaming RPC)

    • 客户端发送一个请求,服务器以流式方式返回多个响应。
    • 客户端可以按顺序逐个处理响应。
    • 适用于服务器生成的数据流,如日志流或实时事件。
  3. 流式请求,单一响应(Client Streaming RPC)

    • 客户端通过流式方式发送多个请求,服务器返回一个单一响应。
    • 用于客户端生成的数据流,例如上传大型文件。
  4. 流式请求,流式响应(Bidirectional Streaming RPC)

    • 客户端和服务器都可以通过流式方式发送和接收多个请求和响应。
    • 这种模式适用于需要双向通信、实时互动的场景。
    • 用于实现聊天应用、游戏服务器等需要实时互动的应用程序。

这四种数据流类型允许您根据具体的需求选择适当的通信方式,以满足不同的应用场景。gRPC使得定义和实现这些不同类型的数据流变得相对容易,而且它们可以在多种编程语言中使用。

二、简单使用示例

1.单一请求,单一响应

下面是一个简单的 gRPC 客户端和服务器的示例,使用 Go 编程语言。这个示例演示了如何创建一个 gRPC 服务和一个客户端,进行一次简单的单一请求单一响应(Unary RPC)通信。在这个示例中,我们将创建一个用于查询用户信息的简单 gRPC 服务。

首先,您需要确保已经安装了 gRPC 和 Protocol Buffers 的 Go 插件。如果没有安装,可以使用以下命令来安装:

go get google.golang.org/grpc
go get github.com/golang/protobuf/protoc-gen-go

然后,您可以创建.proto文件来定义您的服务和消息。例如,创建一个名为 user.proto 的文件:

syntax = "proto3";

package user;

service UserService {
  rpc GetUser (UserRequest) returns (UserResponse);
}

message UserRequest {
  string user_id = 1;
}

message UserResponse {
  string name = 1;
  int32 age = 2;
}

接下来,使用 Protocol Buffers 的编译器来生成 Go 代码:

protoc --go_out=plugins=grpc:. user.proto

现在,您可以编写 gRPC 服务的 Go 代码:

package main

import (
	"context"
	"log"
	"net"
	"google.golang.org/grpc"
	pb "your_package/user" // 修改为您的.proto文件的包名
)

type userServiceServer struct{}

func (s *userServiceServer) GetUser(ctx context.Context, req *pb.UserRequest) (*pb.UserResponse, error) {
	// 这里可以实现获取用户信息的逻辑
	return &pb.UserResponse{
		Name: "John Doe",
		Age:  30,
	}, nil
}

func main() {
	listen, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}

	server := grpc.NewServer()
	pb.RegisterUserServiceServer(server, &userServiceServer{})
	log.Println("Server is running on :50051")
	if err := server.Serve(listen); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}

然后,编写 gRPC 客户端的 Go 代码:

package main

import (
	"context"
	"log"
	"google.golang.org/grpc"
	pb "your_package/user" // 修改为您的.proto文件的包名
)

func main() {
	conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to connect: %v", err)
	}
	defer conn.Close()

	client := pb.NewUserServiceClient(conn)
	request := &pb.UserRequest{
		UserId: "123",
	}

	response, err := client.GetUser(context.Background(), request)
	if err != nil {
		log.Fatalf("Failed to call GetUser: %v", err)
	}

	log.Printf("Name: %s, Age: %d", response.Name, response.Age)
}

确保在代码中将 "your_package/user" 替换为您的实际包名,然后分别运行服务端和客户端代码,您将能够看到 gRPC 单一请求单一响应的工作示例。这只是一个简单的示例,实际上,gRPC 具有更多功能和用例,例如流式通信和身份验证。

2.其他流模式示例

在 gRPC 中,有三种主要的流式模式:服务器流式 RPC、客户端流式 RPC和双向流式 RPC。下面将为每种模式提供一个使用示例。

1. 服务器流式 RPC (Server Streaming RPC):

在服务器流式 RPC 中,服务器向客户端发送一系列的消息。以下是一个示例,其中服务器向客户端发送一系列的数字:

服务端:
package main

import (
	"context"
	"log"
	"net"
	"time"
	"google.golang.org/grpc"
	pb "your_package/numbers" // 请替换为您的.proto文件的包名
)

type numberServiceServer struct{}

func (s *numberServiceServer) GenerateNumbers(req *pb.NumberRequest, stream pb.NumberService_GenerateNumbersServer) error {
	for i := int32(1); i <= req.Count; i++ {
		response := &pb.NumberResponse{Number: i}
		if err := stream.Send(response); err != nil {
			return err
		}
		time.Sleep(1 * time.Second) // 模拟处理时间
	}
	return nil
}

func main() {
	listen, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}

	server := grpc.NewServer()
	pb.RegisterNumberServiceServer(server, &numberServiceServer{})
	log.Println("Server is running on :50051")
	if err := server.Serve(listen); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
客户端:
package main

import (
	"context"
	"log"
	"google.golang.org/grpc"
	pb "your_package/numbers" // 请替换为您的.proto文件的包名
)

func main() {
	conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to connect: %v", err)
	}
	defer conn.Close()

	client := pb.NewNumberServiceClient(conn)

	request := &pb.NumberRequest{Count: 5}
	stream, err := client.GenerateNumbers(context.Background(), request)
	if err != nil {
		log.Fatalf("Failed to call GenerateNumbers: %v", err)
	}

	for {
		response, err := stream.Recv()
		if err != nil {
			break
		}
		log.Printf("Received number: %d", response.Number)
	}
}

2. 客户端流式 RPC (Client Streaming RPC):

在客户端流式 RPC 中,客户端向服务器发送一系列的消息,然后服务器返回一个响应。以下是一个示例,其中客户端向服务器发送一系列的数字,服务器返回它们的总和:

服务端:
package main

import (
	"context"
	"log"
	"net"
	"google.golang.org/grpc"
	pb "your_package/numbers" // 请替换为您的.proto文件的包名
)

type numberServiceServer struct{}

func (s *numberServiceServer) CalculateSum(stream pb.NumberService_CalculateSumServer) error {
	sum := int32(0)
	for {
		request, err := stream.Recv()
		if err != nil {
			break
		}
		sum += request.Number
	}
	response := &pb.NumberResponse{Number: sum}
	return stream.SendAndClose(response)
}

func main() {
	listen, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}

	server := grpc.NewServer()
	pb.RegisterNumberServiceServer(server, &numberServiceServer{})
	log.Println("Server is running on :50051")
	if err := server.Serve(listen); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
客户端:
package main

import (
	"context"
	"log"
	"google.golang.org/grpc"
	pb "your_package/numbers" // 请替换为您的.proto文件的包名
)

func main() {
	conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to connect: %v", err)
	}
	defer conn.Close()

	client := pb.NewNumberServiceClient(conn)

	stream, err := client.CalculateSum(context.Background())
	if err != nil {
		log.Fatalf("Failed to call CalculateSum: %v", err)
	}

	numbers := []int32{1, 2, 3, 4, 5}
	for _, number := range numbers {
		request := &pb.NumberRequest{Number: number}
		if err := stream.Send(request); err != nil {
			log.Fatalf("Failed to send number: %v", err)
		}
	}

	response, err := stream.CloseAndRecv()
	if err != nil {
		log.Fatalf("Failed to receive response: %v", err)
	}

	log.Printf("Sum of numbers: %d", response.Number)
}

3. 双向流式 RPC (Bidirectional Streaming RPC):

在双向流式 RPC 中,客户端和服务器都可以通过流式方式发送和接收多个消息。以下是一个简单的示例,其中客户端和服务器之间交换消息:

服务端:
package main

import (
	"context"
	"log"
	"net"
	"google.golang.org/grpc"
	pb "your_package/chat" // 请替换为您的.proto文件的包名
)

type chatServiceServer struct{}

func (s *chatServiceServer) Chat(stream pb.ChatService_ChatServer) error {
	for {
		message, err := stream.Recv()
		if err != nil {
			return err
		}
		log.Printf("[%s]: %s", message.User, message.Message)

		response := &pb.ChatMessage{
			User:    "Server",
			Message: "Message received",
		}

		if err := stream.Send(response); err != nil {
			return err
		}
	}
}

func main() {
	listen, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}

	server := grpc.NewServer()
	pb.RegisterChatServiceServer(server, &chatServiceServer{})
	log.Println("Server is running on :50051")
	if err := server.Serve(listen); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
客户端:
package main
import (
	"context"
	"log"
	"os"
	"os/signal"
	"google.golang.org/grpc"
	pb "your_package/chat" // 请替换为您的.proto文件的包名
)
func main() {
	conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed
代码如下(示例):
```c
data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

``

要使用 grpc 插件生成 Go 语言的 proto 文件,你需要使用 protoc 命令,并指定 --go_out 和 --go-grpc_out 选项。这些选项会生成相应的 .pb.go 和 .pb.grpc.go 文件。

假设你的 proto 文件名为 helloworld.proto,你可以使用以下命令生成 Go 文件:

bash
复制代码
protoc --go_out=. --go-grpc_out=. helloworld.proto
以下是更详细的步骤:

安装 Protocol Buffers 编译器 (protoc):
你需要安装 protoc。可以从 Protocol Buffers releases page 下载适合你操作系统的版本,并按照说明安装。

安装 Go 插件:
确保你已经安装了 protoc-gen-go 和 protoc-gen-go-grpc 插件。可以使用以下命令安装:

bash
复制代码
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
设置 PATH:
确保你的 GOPATH/bin 目录在系统的 PATH 环境变量中,因为 protoc 会调用这些插件。

生成 Go 文件:
在你的 proto 文件所在目录下运行 protoc 命令:

bash
复制代码
protoc --go_out=. --go-grpc_out=. helloworld.proto
这将生成两个文件:

helloworld.pb.go:包含你的消息类型和基本的序列化/反序列化代码。
helloworld_grpc.pb.go:包含你的 gRPC 服务的接口和客户端代码。
确保你的目录结构正确,这样生成的 Go 文件会被放在适当的位置。例如,如果你的 proto 文件在 proto 目录下,生成的命令应该是:

bash
复制代码
protoc --go_out=. --go-grpc_out=. proto/helloworld.proto
这会在当前目录生成 proto/helloworld.pb.go 和 proto/helloworld_grpc.pb.go 文件。

protobuf生成go文件命令
安装

brew install protobuf

项目中安装grpc插件

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

protoc --go_out=. --go_opt=paths=source_relative \
       --go-grpc_out=. --go-grpc_opt=paths=source_relative \
       hello.proto

总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值