博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
gRPC简介
阅读量:6608 次
发布时间:2019-06-24

本文共 12211 字,大约阅读时间需要 40 分钟。

hot3.png

 

gRPC是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

》原文出自《 》

1.安装protobuf

去到下载最新版本,自行编译,在加入到环境变量中,用于生成proto代码.

windows可以直接在这里编译好的可执行文件.

检测是否安装成功

protoc --versionlibprotoc 3.1.0

 

使用go语言还需要下载golang protobuf和代码生成的plugin工具

go get -u github.com/golang/protobuf/proto // golang protobuf 库go get -u github.com/golang/protobuf/protoc-gen-go //protoc --go_out 工具

安装grpc-go

go get github.com/grpc/grpc-go

在对应的example目录有对应的示例程序。

以route_guide为例,首先看PB描述文件

syntax = "proto3";option java_multiple_files = true;option java_package = "io.grpc.examples.routeguide";option java_outer_classname = "RouteGuideProto";package routeguide;// Interface exported by the server.service RouteGuide {  // 类似普通的函数调用,客户端发送请求Point到服务器,服务器返回相应Feature.  rpc GetFeature(Point) returns (Feature) {}  // 客户端发起一次请求,服务器端返回一个流式数据,比如一个数组中的逐个元素  rpc ListFeatures(Rectangle) returns (stream Feature) {}  // 客户端发起的请求是一个流式的数据,比如数组中的逐个元素,服务器返回一个相应  rpc RecordRoute(stream Point) returns (RouteSummary) {}  // 客户端发起的请求是一个流式数据,比如数组中的逐个元素,二服务器返回的也是一个类似的数据结构  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}}// message用于描述一个消息类型,可以看做一个对象message Point {  // 字段类型 字段名称  int32 latitude = 1;  int32 longitude = 2;}message Rectangle {  Point lo = 1;  Point hi = 2;}message Feature {  string name = 1;  Point location = 2;}message RouteNote {  Point location = 1;  string message = 2;}message RouteSummary {  // 字段命名默认会转换为驼峰方式 如 pointCount  int32 point_count = 1;  int32 feature_count = 2;  int32 distance = 3;  int32 elapsed_time = 4;}

使用protoc命令生成相关文件:

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --javanano_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto--proto_path:代表PB描述文件的目录,多个目录可使用多次引入,可简写为-I=IMPORT_PATH当PB描述文件中import了其他的PB文件时,可用该方式指定导入的路径--cpp_out:c++文件生成的目标目录--java_out:java文件生成的目标目录--python_out:python文件生成的目标目录--go_out:go文件生成的目标目录--ruby_out:ruby文件生成的目标目录--php_out:php文件生成的目标目录protoc3 --go_out=plugins=grpc:go protos\route_guide.proto

生成对应的pb.go文件。这里用了plugins选项,提供对grpc的支持,否则不会生成Service的接口。

java也有对应的plugin支持,可以直接生成Service接口等内容,具体可。

生成接口后,剩下的值需要server端完成实现即可。

服务端程序:

package mainimport (	"encoding/json"	"flag"	"fmt"	"io"	"io/ioutil"	"math"	"net"	"time"	"golang.org/x/net/context"	"google.golang.org/grpc"	"google.golang.org/grpc/credentials"	"google.golang.org/grpc/grpclog"	"github.com/golang/protobuf/proto"	pb "google.golang.org/grpc/examples/route_guide/routeguide")var (	tls        = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")	certFile   = flag.String("cert_file", "../testdata/server1.pem", "The TLS cert file")	keyFile    = flag.String("key_file", "../testdata/server1.key", "The TLS key file")	jsonDBFile = flag.String("json_db_file", "../testdata/route_guide_db.json", "A json file containing a list of features")	port       = flag.Int("port", 10000, "The server port"))type routeGuideServer struct {	savedFeatures []*pb.Feature	routeNotes    map[string][]*pb.RouteNote}func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {	for _, feature := range s.savedFeatures {		if proto.Equal(feature.Location, point) {			return feature, nil		}	}	// No feature was found, return an unnamed feature	return &pb.Feature{Location: point}, nil}func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {	for _, feature := range s.savedFeatures {		if inRange(feature.Location, rect) {			if err := stream.Send(feature); err != nil {				return err			}		}	}	return nil}func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error {	var pointCount, featureCount, distance int32	var lastPoint *pb.Point	startTime := time.Now()	for {		point, err := stream.Recv()		if err == io.EOF {			endTime := time.Now()			return stream.SendAndClose(&pb.RouteSummary{				PointCount:   pointCount,				FeatureCount: featureCount,				Distance:     distance,				ElapsedTime:  int32(endTime.Sub(startTime).Seconds()),			})		}		if err != nil {			return err		}		pointCount++		for _, feature := range s.savedFeatures {			if proto.Equal(feature.Location, point) {				featureCount++			}		}		if lastPoint != nil {			distance += calcDistance(lastPoint, point)		}		lastPoint = point	}}func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {	for {		in, err := stream.Recv()		if err == io.EOF {			return nil		}		if err != nil {			return err		}		key := serialize(in.Location)		if _, present := s.routeNotes[key]; !present {			s.routeNotes[key] = []*pb.RouteNote{in}		} else {			s.routeNotes[key] = append(s.routeNotes[key], in)		}		for _, note := range s.routeNotes[key] {			if err := stream.Send(note); err != nil {				return err			}		}	}}func (s *routeGuideServer) loadFeatures(filePath string) {	file, err := ioutil.ReadFile(filePath)	if err != nil {		grpclog.Fatalf("Failed to load default features: %v", err)	}	if err := json.Unmarshal(file, &s.savedFeatures); err != nil {		grpclog.Fatalf("Failed to load default features: %v", err)	}}func toRadians(num float64) float64 {	return num * math.Pi / float64(180)}func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 {	const CordFactor float64 = 1e7	const R float64 = float64(6371000) // metres	lat1 := float64(p1.Latitude) / CordFactor	lat2 := float64(p2.Latitude) / CordFactor	lng1 := float64(p1.Longitude) / CordFactor	lng2 := float64(p2.Longitude) / CordFactor	φ1 := toRadians(lat1)	φ2 := toRadians(lat2)	Δφ := toRadians(lat2 - lat1)	Δλ := toRadians(lng2 - lng1)	a := math.Sin(Δφ/2)*math.Sin(Δφ/2) +		math.Cos(φ1)*math.Cos(φ2)*			math.Sin(Δλ/2)*math.Sin(Δλ/2)	c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))	distance := R * c	return int32(distance)}func inRange(point *pb.Point, rect *pb.Rectangle) bool {	left := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))	right := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))	top := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))	bottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))	if float64(point.Longitude) >= left &&		float64(point.Longitude) <= right &&		float64(point.Latitude) >= bottom &&		float64(point.Latitude) <= top {		return true	}	return false}func serialize(point *pb.Point) string {	return fmt.Sprintf("%d %d", point.Latitude, point.Longitude)}func newServer() *routeGuideServer {	s := new(routeGuideServer)	s.loadFeatures(*jsonDBFile)	s.routeNotes = make(map[string][]*pb.RouteNote)	return s}func main() {	flag.Parse()	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))	if err != nil {		grpclog.Fatalf("failed to listen: %v", err)	}	var opts []grpc.ServerOption	if *tls {		creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)		if err != nil {			grpclog.Fatalf("Failed to generate credentials %v", err)		}		opts = []grpc.ServerOption{grpc.Creds(creds)}	}	grpcServer := grpc.NewServer(opts...)	pb.RegisterRouteGuideServer(grpcServer, newServer())	grpcServer.Serve(lis)}

客户端程序:

package mainimport (	"flag"	"io"	"math/rand"	"time"	"golang.org/x/net/context"	"google.golang.org/grpc"	"google.golang.org/grpc/credentials"	pb "github.com/grpc/grpc-go/examples/route_guide/routeguide"	"google.golang.org/grpc/grpclog")var (	tls                = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")	caFile             = flag.String("ca_file", "testdata/ca.pem", "The file containning the CA root cert file")	serverAddr         = flag.String("server_addr", "127.0.0.1:10000", "The server address in the format of host:port")	serverHostOverride = flag.String("server_host_override", "x.test.youtube.com", "The server name use to verify the hostname returned by TLS handshake"))// printFeature gets the feature for the given point.func printFeature(client pb.RouteGuideClient, point *pb.Point) {	grpclog.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)	feature, err := client.GetFeature(context.Background(), point)	if err != nil {		grpclog.Fatalf("%v.GetFeatures(_) = _, %v: ", client, err)	}	grpclog.Println(feature)}// printFeatures lists all the features within the given bounding Rectangle.func printFeatures(client pb.RouteGuideClient, rect *pb.Rectangle) {	grpclog.Printf("Looking for features within %v", rect)	stream, err := client.ListFeatures(context.Background(), rect)	if err != nil {		grpclog.Fatalf("%v.ListFeatures(_) = _, %v", client, err)	}	for {		feature, err := stream.Recv()		if err == io.EOF {			break		}		if err != nil {			grpclog.Fatalf("%v.ListFeatures(_) = _, %v", client, err)		}		grpclog.Println(feature)	}}// runRecordRoute sends a sequence of points to server and expects to get a RouteSummary from server.func runRecordRoute(client pb.RouteGuideClient) {	// Create a random number of random points	r := rand.New(rand.NewSource(time.Now().UnixNano()))	pointCount := int(r.Int31n(100)) + 2 // Traverse at least two points	var points []*pb.Point	for i := 0; i < pointCount; i++ {		points = append(points, randomPoint(r))	}	grpclog.Printf("Traversing %d points.", len(points))	stream, err := client.RecordRoute(context.Background())	if err != nil {		grpclog.Fatalf("%v.RecordRoute(_) = _, %v", client, err)	}	for _, point := range points {		if err := stream.Send(point); err != nil {			grpclog.Fatalf("%v.Send(%v) = %v", stream, point, err)		}	}	reply, err := stream.CloseAndRecv()	if err != nil {		grpclog.Fatalf("%v.CloseAndRecv() got error %v, want %v", stream, err, nil)	}	grpclog.Printf("Route summary: %v", reply)}// runRouteChat receives a sequence of route notes, while sending notes for various locations.func runRouteChat(client pb.RouteGuideClient) {	notes := []*pb.RouteNote{		{&pb.Point{Latitude: 0, Longitude: 1}, "First message"},		{&pb.Point{Latitude: 0, Longitude: 2}, "Second message"},		{&pb.Point{Latitude: 0, Longitude: 3}, "Third message"},		{&pb.Point{Latitude: 0, Longitude: 1}, "Fourth message"},		{&pb.Point{Latitude: 0, Longitude: 2}, "Fifth message"},		{&pb.Point{Latitude: 0, Longitude: 3}, "Sixth message"},	}	stream, err := client.RouteChat(context.Background())	if err != nil {		grpclog.Fatalf("%v.RouteChat(_) = _, %v", client, err)	}	waitc := make(chan struct{})	go func() {		for {			in, err := stream.Recv()			if err == io.EOF {				// read done.				close(waitc)				return			}			if err != nil {				grpclog.Fatalf("Failed to receive a note : %v", err)			}			grpclog.Printf("Got message %s at point(%d, %d)", in.Message, in.Location.Latitude, in.Location.Longitude)		}	}()	for _, note := range notes {		if err := stream.Send(note); err != nil {			grpclog.Fatalf("Failed to send a note: %v", err)		}	}	stream.CloseSend()	<-waitc}func randomPoint(r *rand.Rand) *pb.Point {	lat := (r.Int31n(180) - 90) * 1e7	long := (r.Int31n(360) - 180) * 1e7	return &pb.Point{Latitude: lat, Longitude: long}}func main() {	flag.Parse()	var opts []grpc.DialOption	if *tls {		var sn string		if *serverHostOverride != "" {			sn = *serverHostOverride		}		var creds credentials.TransportCredentials		if *caFile != "" {			var err error			creds, err = credentials.NewClientTLSFromFile(*caFile, sn)			if err != nil {				grpclog.Fatalf("Failed to create TLS credentials %v", err)			}		} else {			creds = credentials.NewClientTLSFromCert(nil, sn)		}		opts = append(opts, grpc.WithTransportCredentials(creds))	} else {		opts = append(opts, grpc.WithInsecure())	}	conn, err := grpc.Dial(*serverAddr, opts...)	if err != nil {		grpclog.Fatalf("fail to dial: %v", err)	}	defer conn.Close()	client := pb.NewRouteGuideClient(conn)	// Looking for a valid feature	printFeature(client, &pb.Point{Latitude: 409146138, Longitude: -746188906})	// Feature missing.	printFeature(client, &pb.Point{Latitude: 0, Longitude: 0})	// Looking for features between 40, -75 and 42, -73.	printFeatures(client, &pb.Rectangle{		Lo: &pb.Point{Latitude: 400000000, Longitude: -750000000},		Hi: &pb.Point{Latitude: 420000000, Longitude: -730000000},	})	// RecordRoute	runRecordRoute(client)	// RouteChat	runRouteChat(client)}

 

转载于:https://my.oschina.net/kevinair/blog/820388

你可能感兴趣的文章
Spring Cloud云架构 - SSO单点登录之OAuth2.0 登出流程(3)
查看>>
编程之美 测试赛 石头剪刀布
查看>>
签名问题
查看>>
软件开发各阶段交付物列表
查看>>
2018-05-24 Linux学习
查看>>
ntp服务器的搭建
查看>>
我的友情链接
查看>>
sysstat 安装
查看>>
六、nginx搭建织梦DedeCms网站
查看>>
Tair学习小记
查看>>
网卡绑定(服务器&&交换机),缓存服务器Squid架构配置
查看>>
web网站加速之CDN(Content Delivery Network)技术原理
查看>>
打算写一款框架来提高自己 写个结构吧
查看>>
vue学习:10、第一个项目,实践中遇到的问题
查看>>
sed的基本用法
查看>>
一个不错的shell 脚本入门教程
查看>>
JVM、GC相关资料
查看>>
dell r620装cenots7遇到的问题
查看>>
Ansible之playbook的使用
查看>>
ansible模块批量管理
查看>>