1. Pengantar
Dalam codelab ini, Anda akan menggunakan gRPC-Go untuk membuat klien dan server yang membentuk dasar aplikasi pemetaan rute yang ditulis dalam Go.
Di akhir tutorial, Anda akan memiliki klien yang terhubung ke server jarak jauh menggunakan gRPC untuk mendapatkan informasi tentang fitur di rute klien, membuat ringkasan rute klien, dan bertukar informasi rute seperti info terbaru lalu lintas dengan server dan klien lain.
Layanan ini ditentukan dalam file Protocol Buffers, yang akan digunakan untuk membuat kode boilerplate bagi klien dan server sehingga keduanya dapat berkomunikasi satu sama lain, sehingga menghemat waktu dan upaya Anda dalam menerapkan fungsi tersebut.
Kode yang dihasilkan ini tidak hanya menangani kompleksitas komunikasi antara server dan klien, tetapi juga serialisasi dan deserialisasi data.
Yang akan Anda pelajari
- Cara menggunakan Protocol Buffers untuk menentukan API layanan.
- Cara membangun klien dan server berbasis gRPC dari definisi Protocol Buffers menggunakan pembuatan kode otomatis.
- Pemahaman tentang komunikasi streaming klien-server dengan gRPC.
Codelab ini ditujukan untuk developer Go yang baru menggunakan gRPC atau ingin mempelajari kembali gRPC, atau siapa pun yang tertarik untuk membangun sistem terdistribusi. Tidak diperlukan pengalaman gRPC sebelumnya.
2. Sebelum memulai
Prasyarat
Pastikan Anda telah menginstal berikut ini:
- Rangkaian alat Go versi 1.24.5 atau yang lebih baru. Untuk mengetahui petunjuk penginstalan, lihat Mulai Go.
- Compiler buffer protokol,
protoc
, versi 3.27.1 atau yang lebih baru. Untuk mengetahui petunjuk penginstalan, lihat panduan penginstalan compiler. - Plugin compiler buffering protokol untuk Go dan gRPC. Untuk menginstal plugin ini, jalankan perintah berikut:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Perbarui variabel PATH
agar compiler buffer protokol dapat menemukan plugin:
export PATH="$PATH:$(go env GOPATH)/bin"
Mendapatkan kode
Agar Anda tidak perlu memulai dari awal, codelab ini menyediakan kerangka kode sumber aplikasi yang dapat Anda selesaikan. Langkah-langkah berikut akan menunjukkan cara menyelesaikan aplikasi, termasuk menggunakan plugin compiler buffer protokol untuk membuat kode gRPC boilerplate.
Pertama, buat direktori kerja codelab dan cd
ke dalamnya:
mkdir streaming-grpc-go-getting-started && cd streaming-grpc-go-getting-started
Download dan ekstrak codelab:
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \ | tar xvz --strip-components=4 \ grpc-codelabs-1/codelabs/grpc-go-streaming/start_here
Atau, Anda dapat mendownload file .zip yang hanya berisi direktori codelab dan mengekstraknya secara manual.
Kode sumber yang sudah selesai tersedia di GitHub jika Anda ingin melewati pengetikan implementasi.
3. Menentukan pesan dan layanan
Langkah pertama Anda adalah menentukan layanan gRPC aplikasi, metode RPC, dan jenis pesan permintaan dan responsnya menggunakan Protocol Buffers. Layanan Anda akan menyediakan:
- Metode RPC yang disebut
ListFeatures
,RecordRoute
, danRouteChat
yang diimplementasikan server dan dipanggil klien. - Jenis pesan
Point
,Feature
,Rectangle
,RouteNote
, danRouteSummary
, yang merupakan struktur data yang dipertukarkan antara klien dan server saat memanggil metode di atas.
Metode RPC ini dan jenis pesannya akan ditentukan dalam file routeguide/route_guide.proto
kode sumber yang diberikan.
Protocol Buffers biasanya dikenal sebagai protobuf. Untuk mengetahui informasi selengkapnya tentang terminologi gRPC, lihat Konsep inti, arsitektur, dan siklus proses gRPC.
Menentukan Jenis pesan
Dalam file routeguide/route_guide.proto
kode sumber, tentukan terlebih dahulu jenis pesan Point
. Point
mewakili pasangan koordinat lintang-bujur di peta. Untuk codelab ini, gunakan bilangan bulat untuk koordinat:
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
Angka 1
dan 2
adalah nomor ID unik untuk setiap kolom dalam struktur message
.
Selanjutnya, tentukan jenis pesan Feature
. Feature
menggunakan kolom string
untuk nama atau alamat pos sesuatu di lokasi yang ditentukan oleh Point
:
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
Selanjutnya, pesan Rectangle
yang merepresentasikan persegi panjang lintang-bujur, yang direpresentasikan sebagai dua titik yang berlawanan secara diagonal "lo" dan "hi".
message Rectangle {
// One corner of the rectangle.
Point lo = 1;
// The other corner of the rectangle.
Point hi = 2;
}
Juga pesan RouteNote
yang merepresentasikan pesan yang dikirim pada titik tertentu.
message RouteNote {
// The location from which the message is sent.
Point location = 1;
// The message to be sent.
string message = 2;
}
Kami juga akan memerlukan pesan RouteSummary
. Pesan ini diterima sebagai respons terhadap RPC RecordRoute
yang dijelaskan di bagian berikutnya. Objek ini berisi jumlah titik individual yang diterima, jumlah fitur yang terdeteksi, dan total jarak yang ditempuh sebagai jumlah kumulatif jarak antara setiap titik.
message RouteSummary {
// The number of points received.
int32 point_count = 1;
// The number of known features passed while traversing the route.
int32 feature_count = 2;
// The distance covered in metres.
int32 distance = 3;
// The duration of the traversal in seconds.
int32 elapsed_time = 4;
}
Menentukan metode layanan
Untuk menentukan layanan, Anda menentukan layanan bernama dalam file .proto. File route_guide.proto
memiliki struktur service
bernama RouteGuide
yang menentukan satu atau beberapa metode yang disediakan oleh layanan aplikasi.
Tentukan metode RPC
di dalam definisi layanan Anda, dengan menentukan jenis permintaan dan responsnya. Di bagian codelab ini, mari kita tentukan:
ListFeatures
Mendapatkan Feature
yang tersedia dalam Rectangle
tertentu. Hasil di-streaming, bukan ditampilkan sekaligus (misalnya, dalam pesan respons dengan kolom berulang), karena persegi panjang dapat mencakup area yang luas dan berisi sejumlah besar fitur.
Jenis yang sesuai untuk RPC ini adalah RPC streaming sisi server: klien mengirim permintaan ke server dan mendapatkan aliran untuk membaca kembali urutan pesan. Klien membaca dari stream yang ditampilkan hingga tidak ada lagi pesan. Seperti yang dapat Anda lihat dalam contoh kami, Anda menentukan metode streaming sisi server dengan menempatkan kata kunci stream sebelum jenis respons.
rpc ListFeatures(Rectangle) returns (stream Feature) {}
RecordRoute
Menerima aliran Point
di rute yang dilalui, menampilkan RouteSummary
saat traversal selesai.
RPC streaming sisi klien tampaknya sesuai dalam kasus ini: klien menulis urutan pesan dan mengirimkannya ke server, lagi-lagi menggunakan stream yang disediakan. Setelah klien selesai menulis pesan, klien akan menunggu server membaca semua pesan tersebut dan menampilkan responsnya. Anda menentukan metode streaming sisi klien dengan menempatkan kata kunci stream sebelum jenis permintaan.
rpc RecordRoute(stream Point) returns (RouteSummary) {}
RouteChat
Menerima aliran RouteNote
yang dikirim saat rute sedang dilalui, sambil menerima RouteNote
lainnya (misalnya, dari pengguna lain).
Inilah jenis kasus penggunaan yang tepat untuk streaming dua arah. RPC streaming dua arah membuat kedua sisi mengirim urutan pesan menggunakan stream baca-tulis. Kedua aliran beroperasi secara independen, sehingga klien dan server dapat membaca dan menulis dalam urutan apa pun yang mereka inginkan.
Misalnya, server dapat menunggu untuk menerima semua pesan klien sebelum menulis responsnya, atau dapat membaca pesan lalu menulis pesan secara bergantian, atau kombinasi pembacaan dan penulisan lainnya.
Urutan pesan di setiap aliran akan tetap terjaga. Anda menentukan jenis metode ini dengan menempatkan kata kunci stream sebelum permintaan dan respons.
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
4. Membuat kode klien dan server
Selanjutnya, buat kode gRPC boilerplate untuk klien dan server dari file .proto
menggunakan compiler protocol buffer. Di direktori routeguide
, jalankan:
protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ route_guide.proto
Perintah ini akan menghasilkan file berikut:
route_guide.pb.go
, yang berisi fungsi untuk membuat jenis pesan aplikasi dan mengakses data serta definisi jenis yang merepresentasikan pesan.route_guide_grpc.pb.go
, yang berisi fungsi yang digunakan klien untuk memanggil metode gRPC jarak jauh layanan, dan fungsi yang digunakan oleh server untuk menyediakan layanan jarak jauh tersebut.
Selanjutnya, kita akan menerapkan metode di sisi server, sehingga saat klien mengirim permintaan, server dapat membalas dengan jawaban.
5. Menerapkan layanan
Pertama, mari kita lihat cara membuat server RouteGuide
. Ada dua bagian untuk membuat layanan RouteGuide
kami melakukan tugasnya:
- Mengimplementasikan antarmuka layanan yang dihasilkan dari definisi layanan kita: melakukan "pekerjaan" layanan kita yang sebenarnya.
- Menjalankan server gRPC untuk memproses permintaan dari klien dan mengirimkannya ke implementasi layanan yang tepat.
Mari kita terapkan RouteGuide di server/server.go
.
Mengimplementasikan RouteGuide
Kita perlu menerapkan antarmuka RouteGuideService
yang dihasilkan. Seperti inilah tampilan implementasinya.
type routeGuideServer struct {
...
}
...
func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {
...
}
...
func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error {
...
}
...
func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
...
}
Mari kita pelajari setiap implementasi RPC secara mendetail.
RPC streaming sisi server
Mulai dengan salah satu RPC streaming kami. ListFeatures
adalah RPC streaming sisi server, jadi kita perlu mengirim kembali beberapa Feature
ke klien.
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
}
Seperti yang dapat Anda lihat, alih-alih mendapatkan objek permintaan dan respons sederhana dalam parameter metode, kali ini kita mendapatkan objek permintaan (Rectangle
tempat klien ingin menemukan Features
) dan objek RouteGuide_ListFeaturesServer
khusus untuk menulis respons. Dalam metode ini, kita mengisi sebanyak mungkin objek Feature
yang perlu ditampilkan, dengan menuliskannya ke RouteGuide_ListFeaturesServer
menggunakan metode Send()
. Terakhir, seperti pada RPC sederhana, kita menampilkan error nil
untuk memberi tahu gRPC bahwa kita telah selesai menulis respons. Jika terjadi error dalam panggilan ini, kita akan menampilkan error non-null; lapisan gRPC akan menerjemahkannya ke dalam status RPC yang sesuai untuk dikirim melalui jaringan.
RPC streaming sisi klien
Sekarang mari kita lihat sesuatu yang sedikit lebih rumit: metode streaming sisi klien RecordRoute
, tempat kita mendapatkan aliran Points
dari klien dan menampilkan satu RouteSummary
dengan informasi tentang perjalanannya. Seperti yang dapat Anda lihat, kali ini metode tersebut tidak memiliki parameter permintaan sama sekali. Sebagai gantinya, aplikasi ini mendapatkan aliran RouteGuide_RecordRouteServer
, yang dapat digunakan server untuk membaca dan menulis pesan - aplikasi ini dapat menerima pesan klien menggunakan metode Recv()
dan menampilkan satu respons menggunakan metode SendAndClose()
.
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
}
}
Dalam isi metode, kita menggunakan metode Recv()
RouteGuide_RecordRouteServer
untuk berulang kali membaca permintaan klien ke objek permintaan (dalam hal ini Point
) hingga tidak ada lagi pesan: server perlu memeriksa error yang ditampilkan dari Recv()
setelah setiap panggilan. Jika nilainya nil
, berarti streaming masih bagus dan dapat terus dibaca; jika nilainya io.EOF
, berarti streaming pesan telah berakhir dan server dapat menampilkan RouteSummary
-nya. Jika memiliki nilai lain, kita akan menampilkan error "apa adanya" sehingga akan diterjemahkan ke status RPC oleh lapisan gRPC.
RPC streaming dua arah
Terakhir, mari kita lihat RPC streaming dua arah RouteChat()
.
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)
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 {
if err := stream.Send(note); err != nil {
return err
}
}
}
}
Kali ini kita mendapatkan aliran RouteGuide_RouteChatServer
yang, seperti dalam contoh streaming sisi klien, dapat digunakan untuk membaca dan menulis pesan. Namun, kali ini kita menampilkan nilai melalui stream metode saat klien masih menulis pesan ke stream pesannya. Sintaksis untuk membaca dan menulis di sini sangat mirip dengan metode streaming klien kami, kecuali server menggunakan metode send()
stream, bukan SendAndClose()
karena server menulis beberapa respons. Meskipun setiap sisi akan selalu mendapatkan pesan sisi lain dalam urutan penulisannya, klien dan server dapat membaca dan menulis dalam urutan apa pun — aliran beroperasi sepenuhnya secara independen.
Mulai server
Setelah menerapkan semua metode, kita juga perlu memulai server gRPC agar klien dapat menggunakan layanan kita. Cuplikan berikut menunjukkan cara kami melakukannya untuk layanan RouteGuide
kami:
lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
s := &routeGuideServer{routeNotes: make(map[string][]*pb.RouteNote)}
s.loadFeatures()
pb.RegisterRouteGuideServer(grpcServer, s)
grpcServer.Serve(lis)
Berikut yang terjadi di main()
, langkah demi langkah:
- Tentukan port TCP yang akan digunakan untuk memproses permintaan klien jarak jauh, menggunakan
lis, err := net.Listen(...)
. Secara default, aplikasi menggunakan port TCP50051
seperti yang ditentukan oleh variabelport
atau dengan meneruskan tombol--port
di command line saat menjalankan server. Jika port TCP tidak dapat dibuka, aplikasi akan berakhir dengan error fatal. - Buat instance server gRPC menggunakan
grpc.NewServer(...)
, dan beri nama instance inigrpcServer
. - Buat pointer ke
routeGuideServer
, struktur yang merepresentasikan layanan API aplikasi, dengan memberi nama pointers.
- Gunakan
s.loadFeatures()
untuk mengisi arrays.savedFeatures
. - Daftarkan implementasi layanan kita dengan server gRPC.
- Panggil
Serve()
di server dengan detail port kami untuk melakukan penantian pemblokiran permintaan klien; ini berlanjut hingga proses dihentikan atauStop()
dipanggil.
Fungsi loadFeatures()
mendapatkan pemetaan koordinat ke lokasi dari server/testdata.go
.
6. Buat klien
Sekarang edit client/client.go
, tempat Anda akan menerapkan kode klien.
Untuk memanggil metode layanan jarak jauh, kita harus membuat channel gRPC terlebih dahulu untuk berkomunikasi dengan server. Kita membuatnya dengan meneruskan string URI target server (yang dalam hal ini hanyalah alamat dan nomor port) ke grpc.NewClient()
dalam fungsi main()
klien sebagai berikut:
// Set up a connection to the gRPC server.
conn, err := grpc.NewClient("dns:///"+*serverAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("fail to dial: %v", err)
}
defer conn.Close()
Alamat server, yang ditentukan oleh variabel serverAddr
, secara default adalah localhost:50051
, dan dapat diganti oleh switch --addr
di command line saat menjalankan klien.
Jika klien perlu terhubung ke layanan yang memerlukan kredensial autentikasi, seperti kredensial TLS atau JWT, klien dapat meneruskan objek DialOptions
sebagai parameter ke grpc.NewClient
yang berisi kredensial yang diperlukan. Layanan RouteGuide
tidak memerlukan kredensial apa pun.
Setelah channel gRPC disiapkan, kita memerlukan stub klien untuk melakukan RPC melalui panggilan fungsi Go. Kita mendapatkan stub menggunakan metode NewRouteGuideClient
yang disediakan oleh file route_guide_grpc.pb.go
yang dihasilkan dari file .proto
aplikasi.
import (pb "github.com/grpc-ecosystem/codelabs/getting_started_streaming/routeguide")
client := pb.NewRouteGuideClient(conn)
Panggil metode layanan
Sekarang, mari kita lihat cara memanggil metode layanan. Di gRPC-Go, RPC beroperasi dalam mode pemblokiran/sinkron, yang berarti bahwa panggilan RPC menunggu server merespons, dan akan menampilkan respons atau error.
RPC streaming sisi server
Di sini, kita memanggil metode streaming sisi server ListFeatures
, yang menampilkan aliran objek Feature
geografis.
rect := &pb.Rectangle{ ... } // initialize a pb.Rectangle
log.Printf("Looking for features within %v", rect)
stream, err := client.ListFeatures(context.Background(), rect)
if err != nil {
log.Fatalf("client.ListFeatures failed: %v", err)
}
for {
// For server-to-client streaming RPCs, you call stream.Recv() until it
// returns io.EOF.
feature, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("client.ListFeatures failed: %v", err)
}
log.Printf("Feature: name: %q, point:(%v, %v)", feature.GetName(),
feature.GetLocation().GetLatitude(), feature.GetLocation().GetLongitude())
}
Seperti pada RPC sederhana, kita meneruskan konteks dan permintaan ke metode. Namun, alih-alih mendapatkan objek respons kembali, kita mendapatkan instance RouteGuide_ListFeaturesClient
kembali. Klien dapat menggunakan stream RouteGuide_ListFeaturesClient
untuk membaca respons server. Kita menggunakan metode RouteGuide_ListFeaturesClient
's Recv()
untuk berulang kali membaca respons server ke objek buffer protokol respons (dalam hal ini Feature
) hingga tidak ada lagi pesan: klien perlu memeriksa error err yang ditampilkan dari Recv()
setelah setiap panggilan. Jika nil
, aliran masih bagus dan dapat terus membaca; jika io.EOF
, aliran pesan telah berakhir; jika tidak, pasti ada error RPC, yang diteruskan melalui err
.
RPC streaming sisi klien
Metode streaming sisi klien RecordRoute
mirip dengan metode sisi server, kecuali kita hanya meneruskan konteks metode dan mendapatkan kembali aliran RouteGuide_RecordRouteClient
, yang dapat kita gunakan untuk menulis dan membaca pesan.
// 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))
c2sStream, err := client.RecordRoute(context.TODO())
if err != nil {
log.Fatalf("client.RecordRoute failed: %v", err)
}
// Stream each point to the server.
for _, point := range points {
if err := c2sStream.Send(point); err != nil {
log.Fatalf("client.RecordRoute: stream.Send(%v) failed: %v", point, err)
}
}
// Close the stream and receive the RouteSummary from the server.
reply, err := c2sStream.CloseAndRecv()
if err != nil {
log.Fatalf("client.RecordRoute failed: %v", err)
}
log.Printf("Route summary: %v", reply)
RouteGuide_RecordRouteClient
memiliki metode Send()
yang dapat kita gunakan untuk mengirim permintaan ke server. Setelah selesai menulis permintaan klien ke stream menggunakan Send()
, kita perlu memanggil CloseAndRecv()
di stream untuk memberi tahu gRPC bahwa kita telah selesai menulis dan mengharapkan untuk menerima respons. Kita mendapatkan status RPC dari err yang ditampilkan dari CloseAndRecv()
. Jika statusnya nil
, nilai yang ditampilkan pertama dari CloseAndRecv()
akan menjadi respons server yang valid.
RPC streaming dua arah
Terakhir, mari kita lihat RPC streaming dua arah RouteChat()
. Seperti dalam kasus RecordRoute
, kita hanya meneruskan objek konteks ke metode dan mendapatkan kembali aliran yang dapat kita gunakan untuk menulis dan membaca pesan. Namun, kali ini kita menampilkan nilai melalui aliran metode saat server masih menulis pesan ke aliran pesannya.
biDiStream, err := client.RouteChat(context.Background())
if err != nil {
log.Fatalf("client.RouteChat failed: %v", err)
}
// this channel is used to wait for the receive goroutine to finish.
recvDoneCh := make(chan struct{})
// receive goroutine.
go func() {
for {
in, err := biDiStream.Recv()
if err == io.EOF {
// read done.
close(recvDoneCh)
return
}
if err != nil {
log.Fatalf("client.RouteChat failed: %v", err)
}
log.Printf("Got message %s at point(%d, %d)", in.Message, in.Location.Latitude, in.Location.Longitude)
}
}()
// send messages simultaneously.
for _, note := range notes {
if err := biDiStream.Send(note); err != nil {
log.Fatalf("client.RouteChat: stream.Send(%v) failed: %v", note, err)
}
}
biDiStream.CloseSend()
// wait for the receive goroutine to finish.
<-recvDoneCh
Sintaks untuk membaca dan menulis di sini sangat mirip dengan metode streaming sisi klien, kecuali kita menggunakan metode CloseSend()
stream setelah menyelesaikan panggilan. Meskipun setiap sisi akan selalu mendapatkan pesan sisi lain dalam urutan penulisannya, klien dan server dapat membaca dan menulis dalam urutan apa pun — aliran beroperasi sepenuhnya secara independen.
7. Cobalah
Pastikan server dan klien berfungsi dengan benar satu sama lain dengan menjalankan perintah berikut di direktori kerja aplikasi:
- Jalankan server di satu terminal:
cd server go run .
- Jalankan klien dari terminal lain:
cd client go run .
Anda akan melihat output seperti ini, dengan stempel waktu yang dihilangkan agar lebih jelas:
Looking for features within lo:<latitude:400000000 longitude:-750000000 > hi:<latitude:420000000 longitude:-730000000 > name:"Patriots Path, Mendham, NJ 07945, USA" location:<latitude:407838351 longitude:-746143763 > ... name:"3 Hasta Way, Newton, NJ 07860, USA" location:<latitude:410248224 longitude:-747127767 > Traversing 56 points. Route summary: point_count:56 distance:497013163 Got message First message at point(0, 1) Got message Second message at point(0, 2) Got message Third message at point(0, 3) Got message First message at point(0, 1) Got message Fourth message at point(0, 1) Got message Second message at point(0, 2) Got message Fifth message at point(0, 2) Got message Third message at point(0, 3) Got message Sixth message at point(0, 3)
8. Langkah berikutnya
- Pelajari cara kerja gRPC di Pengantar gRPC dan Konsep inti.
- Pelajari tutorial Dasar-Dasar.
- Pelajari referensi API.