grpc示例代码解析(二)

编程入门 行业动态 更新时间:2024-10-22 21:37:04

一,client.go 客户端主程序

主要内容在注释部分


package main

import (
	"context"
	"flag"
	"io"
	"log"
	"math/rand"
	"time"

	"google.golang/grpc"
	"google.golang/grpc/credentials"
	"google.golang/grpc/credentials/insecure"
	"google.golang/grpc/examples/data"
	pb "google.golang/grpc/examples/route_guide/routeguide"
)

var (
	tls                = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")
	caFile             = flag.String("ca_file", "", "The file containing the CA root cert file")
	serverAddr         = flag.String("addr", "localhost:50051", "The server address in the format of host:port")
	serverHostOverride = flag.String("server_host_override", "x.test.example", "The server name used to verify the hostname returned by the TLS handshake")
)

// 双端一元式
func printFeature(client pb.RouteGuideClient, point *pb.Point) {
	log.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	// 客户端调用双端一元式的函数获取服务端返回结果
	feature, err := client.GetFeature(ctx, point)
	if err != nil {
		log.Fatalf("%v.GetFeatures(_) = _, %v: ", client, err)
	}
	log.Println(feature)
}

// 服务端流式
func printFeatures(client pb.RouteGuideClient, rect *pb.Rectangle) {
	log.Printf("Looking for features within %v", rect)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	// 客户端调用服务端流式的函数获取服务端返回的流
	stream, err := client.ListFeatures(ctx, rect)
	if err != nil {
		log.Fatalf("%v.ListFeatures(_) = _, %v", client, err)
	}
	for {
		// 从流中循环获取服务端写入的内容,直到末尾,Recv方法,在route_guide_grpc.pb.go中实现
		feature, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("%v.ListFeatures(_) = _, %v", client, err)
		}
		log.Printf("Feature: name: %q, point:(%v, %v)", feature.GetName(),
			feature.GetLocation().GetLatitude(), feature.GetLocation().GetLongitude())
	}
}

// 客户端流式
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))
	}
	log.Printf("Traversing %d points.", len(points))
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	// 客户端调用客户端流式的函数获取服务端返回的流
	stream, err := client.RecordRoute(ctx)
	if err != nil {
		log.Fatalf("%v.RecordRoute(_) = _, %v", client, err)
	}
	for _, point := range points {
		// 多次往流中写入内容,Send方法,在route_guide_grpc.pb.go中实现
		if err := stream.Send(point); err != nil {
			log.Fatalf("%v.Send(%v) = %v", stream, point, err)
		}
	}
	// 关闭流,并获取服务端的返回结果,CloseAndRecv方法,在route_guide_grpc.pb.go中实现
	reply, err := stream.CloseAndRecv()
	if err != nil {
		log.Fatalf("%v.CloseAndRecv() got error %v, want %v", stream, err, nil)
	}
	log.Printf("Route summary: %v", reply)
}

// 双端双流式
func runRouteChat(client pb.RouteGuideClient) {
	notes := []*pb.RouteNote{
		{Location: &pb.Point{Latitude: 0, Longitude: 1}, Message: "First message"},
		{Location: &pb.Point{Latitude: 0, Longitude: 2}, Message: "Second message"},
		{Location: &pb.Point{Latitude: 0, Longitude: 3}, Message: "Third message"},
		{Location: &pb.Point{Latitude: 0, Longitude: 1}, Message: "Fourth message"},
		{Location: &pb.Point{Latitude: 0, Longitude: 2}, Message: "Fifth message"},
		{Location: &pb.Point{Latitude: 0, Longitude: 3}, Message: "Sixth message"},
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	// 客户端调用双端双流式的函数,获取服务端返回的流
	stream, err := client.RouteChat(ctx)
	if err != nil {
		log.Fatalf("%v.RouteChat(_) = _, %v", client, err)
	}
	waitc := make(chan struct{})
	go func() {
		for {
			// 单起一个协程,从流中获取服务端输入的内容,Recv方法,在route_guide_grpc.pb.go中实现
			in, err := stream.Recv()
			if err == io.EOF {
				close(waitc) // 表示流读取内容完成
				return
			}
			if err != nil {
				log.Fatalf("Failed to receive a note : %v", err)
			}
			log.Printf("Got message %s at point(%d, %d)", in.Message, in.Location.Latitude, in.Location.Longitude)
		}
	}()
	for _, note := range notes {
		// 多次往流中写入内容发送到服务端,Send方法,在route_guide_grpc.pb.go中实现
		if err := stream.Send(note); err != nil {
			log.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 {
		// grpc支持tls连接,通过ca证书验证
		if *caFile == "" {
			*caFile = data.Path("x509/ca_cert.pem")
		}
		creds, err := credentials.NewClientTLSFromFile(*caFile, *serverHostOverride)
		if err != nil {
			log.Fatalf("Failed to create TLS credentials %v", err)
		}
		opts = append(opts, grpc.WithTransportCredentials(creds))
	} else {
		opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
	}

	// 与grpc服务端创建连接
	conn, err := grpc.Dial(*serverAddr, opts...)
	if err != nil {
		log.Fatalf("fail to dial: %v", err)
	}
	defer conn.Close()
	// 从grpc连接中创建某个服务的客户端,当前服务为RouteGuideClient(可以从一个grpc服务中创建多个服务的客户端)
	client := pb.NewRouteGuideClient(conn)

	// 双端一元式
	printFeature(client, &pb.Point{Latitude: 409146138, Longitude: -746188906})
	printFeature(client, &pb.Point{Latitude: 0, Longitude: 0})

	// 服务端流式
	printFeatures(client, &pb.Rectangle{
		Lo: &pb.Point{Latitude: 400000000, Longitude: -750000000},
		Hi: &pb.Point{Latitude: 420000000, Longitude: -730000000},
	})

	// 客户端流式
	runRecordRoute(client)

	// 双端双流式
	runRouteChat(client)
}

二、server.go 服务端主程序


package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"net"
	"sync"
	"time"

	"google.golang/grpc"

	"google.golang/grpc/credentials"
	"google.golang/grpc/examples/data"

	"github/golang/protobuf/proto"

	pb "google.golang/grpc/examples/route_guide/routeguide"
)

var (
	tls        = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")
	certFile   = flag.String("cert_file", "", "The TLS cert file")
	keyFile    = flag.String("key_file", "", "The TLS key file")
	jsonDBFile = flag.String("json_db_file", "", "A json file containing a list of features")
	port       = flag.Int("port", 50051, "The server port")
)

// 服务端结构体,继承route_guide_grpc.pb.go中未实现的服务端结构体UnimplementedRouteGuideServer
// 并重写了其声明的方法,即服务端处理客户端请求的逻辑体,成为其子类,以实现多态
type routeGuideServer struct {
	pb.UnimplementedRouteGuideServer
	savedFeatures []*pb.Feature // read-only after initialized

	mu         sync.Mutex // protects routeNotes
	routeNotes map[string][]*pb.RouteNote
}

// 双端一流式,重写了UnimplementedRouteGuideServer的该方法
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
}

// 服务端流式,重写了UnimplementedRouteGuideServer的该方法
func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {
	for _, feature := range s.savedFeatures {
		if inRange(feature.Location, rect) {
			// 多次往流中写入内容,Send方法,在route_guide_grpc.pb.go中实现
			if err := stream.Send(feature); err != nil {
				return err
			}
		}
	}
	return nil
}

// 客户端流式,重写了UnimplementedRouteGuideServer的该方法
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()
			// 流读取完毕,返回结果并关闭流,SendAndClose方法,在route_guide_grpc.pb.go中实现
			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
	}
}

// 双端双流式,重写了UnimplementedRouteGuideServer的该方法
func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
	for {
		// 多次从流中获取客户端写入的内容,Recv方法,在route_guide_grpc.pb.go中实现
		in, err := stream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		key := serialize(in.Location)

		s.mu.Lock()
		s.routeNotes[key] = append(s.routeNotes[key], in)
		// Note: this copy prevents blocking other clients while serving this one.
		// We don't need to do a deep copy, because elements in the slice are
		// insert-only and never modified.
		rn := make([]*pb.RouteNote, len(s.routeNotes[key]))
		copy(rn, s.routeNotes[key])
		s.mu.Unlock()

		for _, note := range rn {
			// 多次往流中写入内容,Send方法,在route_guide_grpc.pb.go中实现
			if err := stream.Send(note); err != nil {
				return err
			}
		}
	}
}

// loadFeatures loads features from a JSON file.
func (s *routeGuideServer) loadFeatures(filePath string) {
	var data []byte
	if filePath != "" {
		var err error
		data, err = ioutil.ReadFile(filePath)
		if err != nil {
			log.Fatalf("Failed to load default features: %v", err)
		}
	} else {
		data = exampleData
	}
	if err := json.Unmarshal(data, &s.savedFeatures); err != nil {
		log.Fatalf("Failed to load default features: %v", err)
	}
}

func toRadians(num float64) float64 {
	return num * math.Pi / float64(180)
}

// calcDistance calculates the distance between two points using the "haversine" formula.
// The formula is based on http://mathforum/library/drmath/view/51879.html.
func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 {
	const CordFactor float64 = 1e7
	const R = float64(6371000) // earth radius in metres
	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.Sin(dlng/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 := &routeGuideServer{routeNotes: make(map[string][]*pb.RouteNote)}
	s.loadFeatures(*jsonDBFile)
	return s
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	var opts []grpc.ServerOption
	if *tls {
		// 判断是否需要tls验证
		if *certFile == "" {
			*certFile = data.Path("x509/server_cert.pem")
		}
		if *keyFile == "" {
			*keyFile = data.Path("x509/server_key.pem")
		}
		creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)
		if err != nil {
			log.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	// 创建一个grpc服务
	grpcServer := grpc.NewServer(opts...)
	// 将当前服务注册到grpc服务中
	pb.RegisterRouteGuideServer(grpcServer, newServer())
	// grpc服务接收监听到的连接,并创建一个单独的协程,然后调用已注册的处理程序来响应
	grpcServer.Serve(lis)
}

// exampleData is a copy of testdata/route_guide_db.json. It's to avoid
// specifying file path with `go run`.
var exampleData = []byte(`[{
    "location": {
        "latitude": 407838351,
        "longitude": -746143763
    },
    "name": "Patriots Path, Mendham, NJ 07945, USA"
}, {
    "location": {
        "latitude": 408122808,
        "longitude": -743999179
    },
    "name": "101 New Jersey 10, Whippany, NJ 07981, USA"
}, {
    "location": {
        "latitude": 413628156,
        "longitude": -749015468
    },
    "name": "U.S. 6, Shohola, PA 18458, USA"
}, {
    "location": {
        "latitude": 419999544,
        "longitude": -740371136
    },
    "name": "5 Conners Road, Kingston, NY 12401, USA"
}, {
    "location": {
        "latitude": 414008389,
        "longitude": -743951297
    },
    "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
}, {
    "location": {
        "latitude": 419611318,
        "longitude": -746524769
    },
    "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
}, {
    "location": {
        "latitude": 406109563,
        "longitude": -742186778
    },
    "name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
}, {
    "location": {
        "latitude": 416802456,
        "longitude": -742370183
    },
    "name": "352 South Mountain Road, Wallkill, NY 12589, USA"
}, {
    "location": {
        "latitude": 412950425,
        "longitude": -741077389
    },
    "name": "Bailey Turn Road, Harriman, NY 10926, USA"
}, {
    "location": {
        "latitude": 412144655,
        "longitude": -743949739
    },
    "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
}, {
    "location": {
        "latitude": 415736605,
        "longitude": -742847522
    },
    "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
}, {
    "location": {
        "latitude": 413843930,
        "longitude": -740501726
    },
    "name": "162 Merrill Road, Highland Mills, NY 10930, USA"
}, {
    "location": {
        "latitude": 410873075,
        "longitude": -744459023
    },
    "name": "Clinton Road, West Milford, NJ 07480, USA"
}, {
    "location": {
        "latitude": 412346009,
        "longitude": -744026814
    },
    "name": "16 Old Brook Lane, Warwick, NY 10990, USA"
}, {
    "location": {
        "latitude": 402948455,
        "longitude": -747903913
    },
    "name": "3 Drake Lane, Pennington, NJ 08534, USA"
}, {
    "location": {
        "latitude": 406337092,
        "longitude": -740122226
    },
    "name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
}, {
    "location": {
        "latitude": 406421967,
        "longitude": -747727624
    },
    "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
}, {
    "location": {
        "latitude": 416318082,
        "longitude": -749677716
    },
    "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
}, {
    "location": {
        "latitude": 415301720,
        "longitude": -748416257
    },
    "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
}, {
    "location": {
        "latitude": 402647019,
        "longitude": -747071791
    },
    "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
}, {
    "location": {
        "latitude": 412567807,
        "longitude": -741058078
    },
    "name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
}, {
    "location": {
        "latitude": 416855156,
        "longitude": -744420597
    },
    "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
}, {
    "location": {
        "latitude": 404663628,
        "longitude": -744820157
    },
    "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
}, {
    "location": {
        "latitude": 407113723,
        "longitude": -749746483
    },
    "name": ""
}, {
    "location": {
        "latitude": 402133926,
        "longitude": -743613249
    },
    "name": ""
}, {
    "location": {
        "latitude": 400273442,
        "longitude": -741220915
    },
    "name": ""
}, {
    "location": {
        "latitude": 411236786,
        "longitude": -744070769
    },
    "name": ""
}, {
    "location": {
        "latitude": 411633782,
        "longitude": -746784970
    },
    "name": "211-225 Plains Road, Augusta, NJ 07822, USA"
}, {
    "location": {
        "latitude": 415830701,
        "longitude": -742952812
    },
    "name": ""
}, {
    "location": {
        "latitude": 413447164,
        "longitude": -748712898
    },
    "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
}, {
    "location": {
        "latitude": 405047245,
        "longitude": -749800722
    },
    "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
}, {
    "location": {
        "latitude": 418858923,
        "longitude": -746156790
    },
    "name": ""
}, {
    "location": {
        "latitude": 417951888,
        "longitude": -748484944
    },
    "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
}, {
    "location": {
        "latitude": 407033786,
        "longitude": -743977337
    },
    "name": "26 East 3rd Street, New Providence, NJ 07974, USA"
}, {
    "location": {
        "latitude": 417548014,
        "longitude": -740075041
    },
    "name": ""
}, {
    "location": {
        "latitude": 410395868,
        "longitude": -744972325
    },
    "name": ""
}, {
    "location": {
        "latitude": 404615353,
        "longitude": -745129803
    },
    "name": ""
}, {
    "location": {
        "latitude": 406589790,
        "longitude": -743560121
    },
    "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
}, {
    "location": {
        "latitude": 414653148,
        "longitude": -740477477
    },
    "name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
}, {
    "location": {
        "latitude": 405957808,
        "longitude": -743255336
    },
    "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
}, {
    "location": {
        "latitude": 411733589,
        "longitude": -741648093
    },
    "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
}, {
    "location": {
        "latitude": 412676291,
        "longitude": -742606606
    },
    "name": "1270 Lakes Road, Monroe, NY 10950, USA"
}, {
    "location": {
        "latitude": 409224445,
        "longitude": -748286738
    },
    "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
}, {
    "location": {
        "latitude": 406523420,
        "longitude": -742135517
    },
    "name": "652 Garden Street, Elizabeth, NJ 07202, USA"
}, {
    "location": {
        "latitude": 401827388,
        "longitude": -740294537
    },
    "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
}, {
    "location": {
        "latitude": 410564152,
        "longitude": -743685054
    },
    "name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
}, {
    "location": {
        "latitude": 408472324,
        "longitude": -740726046
    },
    "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
}, {
    "location": {
        "latitude": 412452168,
        "longitude": -740214052
    },
    "name": "5 White Oak Lane, Stony Point, NY 10980, USA"
}, {
    "location": {
        "latitude": 409146138,
        "longitude": -746188906
    },
    "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
}, {
    "location": {
        "latitude": 404701380,
        "longitude": -744781745
    },
    "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
}, {
    "location": {
        "latitude": 409642566,
        "longitude": -746017679
    },
    "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
}, {
    "location": {
        "latitude": 408031728,
        "longitude": -748645385
    },
    "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
}, {
    "location": {
        "latitude": 413700272,
        "longitude": -742135189
    },
    "name": "367 Prospect Road, Chester, NY 10918, USA"
}, {
    "location": {
        "latitude": 404310607,
        "longitude": -740282632
    },
    "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
}, {
    "location": {
        "latitude": 409319800,
        "longitude": -746201391
    },
    "name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
}, {
    "location": {
        "latitude": 406685311,
        "longitude": -742108603
    },
    "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
}, {
    "location": {
        "latitude": 419018117,
        "longitude": -749142781
    },
    "name": "43 Dreher Road, Roscoe, NY 12776, USA"
}, {
    "location": {
        "latitude": 412856162,
        "longitude": -745148837
    },
    "name": "Swan Street, Pine Island, NY 10969, USA"
}, {
    "location": {
        "latitude": 416560744,
        "longitude": -746721964
    },
    "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
}, {
    "location": {
        "latitude": 405314270,
        "longitude": -749836354
    },
    "name": ""
}, {
    "location": {
        "latitude": 414219548,
        "longitude": -743327440
    },
    "name": ""
}, {
    "location": {
        "latitude": 415534177,
        "longitude": -742900616
    },
    "name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
}, {
    "location": {
        "latitude": 406898530,
        "longitude": -749127080
    },
    "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
}, {
    "location": {
        "latitude": 407586880,
        "longitude": -741670168
    },
    "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
}, {
    "location": {
        "latitude": 400106455,
        "longitude": -742870190
    },
    "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
}, {
    "location": {
        "latitude": 400066188,
        "longitude": -746793294
    },
    "name": ""
}, {
    "location": {
        "latitude": 418803880,
        "longitude": -744102673
    },
    "name": "40 Mountain Road, Napanoch, NY 12458, USA"
}, {
    "location": {
        "latitude": 414204288,
        "longitude": -747895140
    },
    "name": ""
}, {
    "location": {
        "latitude": 414777405,
        "longitude": -740615601
    },
    "name": ""
}, {
    "location": {
        "latitude": 415464475,
        "longitude": -747175374
    },
    "name": "48 North Road, Forestburgh, NY 12777, USA"
}, {
    "location": {
        "latitude": 404062378,
        "longitude": -746376177
    },
    "name": ""
}, {
    "location": {
        "latitude": 405688272,
        "longitude": -749285130
    },
    "name": ""
}, {
    "location": {
        "latitude": 400342070,
        "longitude": -748788996
    },
    "name": ""
}, {
    "location": {
        "latitude": 401809022,
        "longitude": -744157964
    },
    "name": ""
}, {
    "location": {
        "latitude": 404226644,
        "longitude": -740517141
    },
    "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
}, {
    "location": {
        "latitude": 410322033,
        "longitude": -747871659
    },
    "name": ""
}, {
    "location": {
        "latitude": 407100674,
        "longitude": -747742727
    },
    "name": ""
}, {
    "location": {
        "latitude": 418811433,
        "longitude": -741718005
    },
    "name": "213 Bush Road, Stone Ridge, NY 12484, USA"
}, {
    "location": {
        "latitude": 415034302,
        "longitude": -743850945
    },
    "name": ""
}, {
    "location": {
        "latitude": 411349992,
        "longitude": -743694161
    },
    "name": ""
}, {
    "location": {
        "latitude": 404839914,
        "longitude": -744759616
    },
    "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
}, {
    "location": {
        "latitude": 414638017,
        "longitude": -745957854
    },
    "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
}, {
    "location": {
        "latitude": 412127800,
        "longitude": -740173578
    },
    "name": ""
}, {
    "location": {
        "latitude": 401263460,
        "longitude": -747964303
    },
    "name": ""
}, {
    "location": {
        "latitude": 412843391,
        "longitude": -749086026
    },
    "name": ""
}, {
    "location": {
        "latitude": 418512773,
        "longitude": -743067823
    },
    "name": ""
}, {
    "location": {
        "latitude": 404318328,
        "longitude": -740835638
    },
    "name": "42-102 Main Street, Belford, NJ 07718, USA"
}, {
    "location": {
        "latitude": 419020746,
        "longitude": -741172328
    },
    "name": ""
}, {
    "location": {
        "latitude": 404080723,
        "longitude": -746119569
    },
    "name": ""
}, {
    "location": {
        "latitude": 401012643,
        "longitude": -744035134
    },
    "name": ""
}, {
    "location": {
        "latitude": 404306372,
        "longitude": -741079661
    },
    "name": ""
}, {
    "location": {
        "latitude": 403966326,
        "longitude": -748519297
    },
    "name": ""
}, {
    "location": {
        "latitude": 405002031,
        "longitude": -748407866
    },
    "name": ""
}, {
    "location": {
        "latitude": 409532885,
        "longitude": -742200683
    },
    "name": ""
}, {
    "location": {
        "latitude": 416851321,
        "longitude": -742674555
    },
    "name": ""
}, {
    "location": {
        "latitude": 406411633,
        "longitude": -741722051
    },
    "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
}, {
    "location": {
        "latitude": 413069058,
        "longitude": -744597778
    },
    "name": "261 Van Sickle Road, Goshen, NY 10924, USA"
}, {
    "location": {
        "latitude": 418465462,
        "longitude": -746859398
    },
    "name": ""
}, {
    "location": {
        "latitude": 411733222,
        "longitude": -744228360
    },
    "name": ""
}, {
    "location": {
        "latitude": 410248224,
        "longitude": -747127767
    },
    "name": "3 Hasta Way, Newton, NJ 07860, USA"
}]`)

更多推荐

grpc示例代码解析(二)

本文发布于:2023-06-14 08:45:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1457897.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:示例   代码   grpc

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!