一 案例概述
pb文件中定义了4个message(结构体)和4个service(方法),为了实现一个向导服务,服务名为RouteGuide,具体如下:
messages:
1. Point 一个点
2. Rectangle 一个区域
3. Feature 特点
4. RouteSummary 多个点的集合(路线)
Services:
unary:
1. GetFeature 参数: 一个(Point) 返回值: 一个(这个Point的Feature)
server side stream:
2. ListFeatures 参数: 一个(Rectangle) 返回值: 输出流(这个区域内所有的feature)
client siede stream:
3. RecordRoute 参数: 输入流(每个时间点的point) 返回值: 一个(RouteSummary)
bidirectional stream:
4. Recommand 参数: 输入流(RecommandationRequst) 返回值: 输出流(Feature)
二 案例实现
1.工程目录
# tree
.
├── go.mod
├── go.sum
├── main.go
├── pbfile
│ └── route
│ ├── goout.sh
│ ├── route_grpc.pb.go
│ ├── route.pb.go
│ └── route.proto
├── route-client
│ └── client.go
└── route-server
└── server.go
2.Pbfile
2.1 route.proto
syntax = "proto3";
package route;
option go_package = "/root/go/src/third/net/grpc-example/pbfile/route";
message Point{
int32 longitude = 1;
int32 latitude = 2;
}
message Rectangle{
Point low = 1;
Point high = 2;
}
message Feature{
string name = 1;
Point location =2;
}
message RouteSummary{
int32 point_count = 1;
int32 distance = 2;
int32 elapsed_time = 3;
}
enum RecommandationMode {
GetFarthest = 0;
GetNearest = 1;
}
message RecommandationRequest{
// 以什么模式推荐
RecommandationMode mode = 1;
// 获取什么点的推荐
Point point = 2;
}
service RouteGuide{
rpc GetFeature(Point) returns (Feature) {}
rpc ListFeatures(Rectangle) returns (stream Feature) {}
rpc RecordRoute(stream Point) returns (RouteSummary) {}
rpc Recommand(stream RecommandationRequest) returns (stream Feature) {}
}
2.2 goout.sh
#!/bin/bash
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative *.proto
3.Server端
package routeServer
import (
"context"
"errors"
"io"
"math"
"net"
"third/net/grpc-example/pbfile/route"
"time"
"github.com/golang/protobuf/proto"
"google.golang.org/grpc"
log "github.com/sirupsen/logrus" // 重命名为log
)
// 检查一个点是否在一个rectangle区间内
func inRange(point *route.Point, rectangle *route.Rectangle) bool {
left := math.Min(float64(rectangle.Low.Longitude), float64(rectangle.High.Longitude))
right := math.Max(float64(rectangle.Low.Longitude), float64(rectangle.High.Longitude))
top := math.Max(float64(rectangle.Low.Latitude), float64(rectangle.High.Latitude))
bottom := math.Min(float64(rectangle.Low.Latitude), float64(rectangle.High.Latitude))
if float64(point.Longitude) >= left &&
float64(point.Longitude) <= right &&
float64(point.Latitude) <= top &&
float64(point.Latitude) >= bottom {
return true
}
return false
}
// 给定两个点(每个点由精度和维度表示),计算地球上该两点之间的距离(meters)
func toRadians(num float64) float64 {
return num * math.Pi / float64(180)
}
func calcDistance(p1, p2 *route.Point) int32 {
const CordFactor float64 = 1e7
const R = float64(6371000) // 地球半径(单位米)
lat1 := toRadians(float64(p1.Latitude) / CordFactor)
lat2 := toRadians(float64(p2.Latitude) / CordFactor)
lng1 := toRadians(float64(p1.Longitude) / CordFactor)
lng2 := toRadians(float64(p2.Longitude) / CordFactor)
dlat := lat2 - lat1
dlng := lng2 - lng1
a := math.Sin(dlat/2)*math.Sin(dlat/2) +
math.Cos(lat1)*math.Cos(lat2)*
math.Sin(dlng/2)*math