1. Pengantar
Dalam codelab ini, Anda akan menggunakan gRPC-Rust untuk membuat klien dan server yang membentuk dasar aplikasi pemetaan rute yang ditulis dalam Rust.
Pada akhir tutorial ini, 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 update lalu lintas dengan server dan klien lainnya.
Layanan ini ditentukan dalam file Protocol Buffers, yang akan digunakan untuk membuat kode boilerplate untuk klien dan server sehingga keduanya dapat berkomunikasi satu sama lain, sehingga Anda dapat menghemat waktu dan upaya dalam menerapkan fungsi tersebut.
Kode yang dihasilkan ini menangani tidak hanya 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 mem-build 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 Rust yang baru menggunakan gRPC atau ingin mempelajari kembali gRPC, atau siapa pun yang tertarik untuk mem-build sistem terdistribusi. Tidak diperlukan pengalaman gRPC sebelumnya.
2. Sebelum memulai
Prasyarat
Pastikan Anda telah menginstal hal berikut:
- GCC. Ikuti petunjuk di sini.
- Git: petunjuk penginstalan di sini.
- Rust, versi 1.88.0. Ikuti petunjuk penginstalan di sini.
Mendapatkan kode
Agar Anda tidak perlu memulai dari awal, codelab ini menyediakan kerangka kode sumber aplikasi untuk Anda selesaikan. Langkah-langkah berikut akan menunjukkan cara menyelesaikan aplikasi, termasuk menggunakan plugin compiler protocol buffer untuk membuat kode gRPC boilerplate.
Pertama, buat direktori kerja codelab dan cd ke dalamnya:
mkdir streaming-grpc-rust-getting-started && cd streaming-grpc-rust-getting-started
Download dan ekstrak codelab:
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/2026.tar.gz \
| tar xvz --strip-components=4 \
grpc-codelabs-2026/codelabs/grpc-rust-streaming/start_here
Atau, Anda dapat mendownload file .zip yang hanya berisi direktori codelab dan mengekstraknya secara manual.
Kode sumber yang telah 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-nya, dan jenis pesan permintaan dan responsnya menggunakan Protocol Buffers. Layanan Anda akan menyediakan:
- Metode RPC yang disebut
ListFeatures,RecordRoute, danRouteChatyang diterapkan 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 proto/routeguide.proto dari kode sumber yang disediakan.
Protocol Buffers biasanya dikenal sebagai protobuf. Untuk mengetahui informasi selengkapnya tentang terminologi gRPC, lihat Konsep inti, arsitektur, dan siklus proses gRPC.
Menentukan jenis Pesan
Pertama, mari kita tentukan pesan yang akan digunakan oleh RPC kita. Dalam file proto/routeguide.proto kode sumber, tentukan terlebih dahulu jenis pesan Point. Point mewakili pasangan koordinat lintang-bujur pada 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 mewakili 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 mewakili pesan yang dikirim saat berada di titik tertentu.
message RouteNote {
// The location from which the message is sent.
Point location = 1;
// The message to be sent.
string message = 2;
}
Kita juga memerlukan pesan RouteSummary. Pesan ini diterima sebagai respons terhadap RecordRoute RPC yang dijelaskan di bagian berikutnya. Pesan 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
Pertama, mari kita tentukan layanan kita, lalu tentukan pesan kita nanti. Untuk menentukan layanan, Anda harus menentukan layanan bernama dalam file .proto. File proto/routeguide.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 yang diberikan. Hasilnya di-streaming, bukan langsung ditampilkan (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 streaming untuk membaca urutan pesan kembali. Klien membaca dari streaming 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 streaming Point di rute yang dilalui, menampilkan RouteSummary saat perjalanan selesai.
RPC streaming sisi klien tampaknya sesuai dalam hal ini: klien menulis urutan pesan dan mengirimkannya ke server, sekali lagi menggunakan streaming yang disediakan. Setelah klien selesai menulis pesan, klien akan menunggu server membaca semuanya 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 streaming RouteNote yang dikirim saat rute dilalui, sambil menerima RouteNote lainnya (misalnya, dari pengguna lain).
Ini adalah jenis kasus penggunaan yang tepat untuk streaming dua arah. RPC streaming dua arah memiliki kedua sisi yang mengirim urutan pesan menggunakan streaming baca-tulis. Kedua streaming 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 secara bergantian, lalu menulis pesan, atau kombinasi baca dan tulis lainnya.
Urutan pesan di setiap streaming dipertahankan. 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
Kami telah memberikan kode yang dihasilkan dari file .proto di direktori generated/, termasuk semua penambahan yang Anda buat di atas. Namun, kami ingin meluangkan waktu untuk menjelaskan cara kerja pembuatan kode.
File .proto kami menjelaskan semua struct dan fungsi yang digunakan klien atau server. Kami menggunakan skrip build Cargo (build.rs) bersama dengan crate grpc-protobuf-build untuk membuat kode ini secara otomatis.
Di Cargo.toml, kami telah menambahkan grpc-protobuf-build sebagai dependensi build.
Di build.rs, kami mengonfigurasi grpc_protobuf_build::CodeGen untuk mengompilasi proto/routeguide.proto ke dalam direktori generated/. Baris kuncinya ada di sini:
grpc_protobuf_build::CodeGen::new()
.include("proto")
.input("routeguide.proto")
.output_dir("generated")
.compile()
.unwrap();
Tindakan ini memanggil pembuatan kode crate grpc_protobuf_build, dan meneruskan routeguide.proto. Kami telah menggabungkannya dalam beberapa kode agar hanya berjalan saat tombol fitur diteruskan, sehingga hanya dibuat ulang saat Anda menginginkannya. Anda tidak perlu menjalankannya sekarang, karena kami telah membuat kode untuk Anda.
cargo build --bin routeguide-server --features regenerate_proto
Saat Anda menjalankan cargo build, build.rs akan mengompilasi definisi protocol buffer ke dalam direktori generate/, termasuk:
- Definisi struct untuk jenis pesan
PointdanFeature. - Fitur layanan Tonic yang perlu kita terapkan untuk server:
route_guide_server::RouteGuide. - Jenis klien gRPC-Rust yang akan kita gunakan untuk memanggil server:
route_guide_client::RouteGuideClient<T>.
Anda dapat melihat panduan protoc-gen-rust-grpc untuk mengetahui informasi selengkapnya.
Selanjutnya, kita akan menerapkan metode layanan di server.
5. Mengimplementasikan layanan
Pertama, mari kita lihat cara membuat server RouteGuide. Ada dua bagian untuk membuat layanan RouteGuide 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 metode yang tepat.
Di src/server/server.rs, kita dapat memasukkan kode yang dihasilkan ke dalam cakupan melalui makro include_generated_proto! gRPC dan mengimpor fitur RouteGuide dan Point.
mod grpc_pb {
grpc::include_generated_proto!("generated", "routeguide");
}
pub use grpc_pb::{
route_guide_server::{RouteGuideServer, RouteGuide},
Point, Feature, Rectangle, RouteNote, RouteSummary
};
Kita dapat memulai dengan menentukan struct untuk mewakili layanan kita. Untuk saat ini, kita dapat melakukannya di src/server/server.rs:
#[derive(Debug)]
pub struct RouteGuideService {
features: Vec<Feature>,
}
Sekarang, kita perlu mengimplementasikan fitur route_guide_server::RouteGuide dari kode yang dihasilkan.
Mengimplementasikan RouteGuide
Kita perlu mengimplementasikan antarmuka RouteGuide yang dihasilkan. Tampilan implementasinya akan seperti ini. Hal ini sudah ada dalam template.
#[tonic::async_trait]
impl RouteGuide for RouteGuideService {
async fn list_features(
&self,
request: Request<Rectangle>,
) -> Result<Response<ListFeaturesStream>, Status> {
...
}
async fn record_route(
&self,
request: Request<tonic::Streaming<Point>>,
) -> Result<Response<RouteSummary>, Status> {
...
}
async fn route_chat(
&self,
request: Request<tonic::Streaming<RouteNote>>,
) -> Result<Response<RouteChatStream>, Status> {
...
}
}
Mari kita lihat setiap implementasi RPC secara mendetail.
RPC streaming sisi server: ListFeatures
Mari kita mulai dengan ListFeatures. Ini adalah RPC streaming sisi server (klien akan mengirim satu pesan, server akan merespons dengan banyak pesan), jadi kita perlu mengirim kembali beberapa Feature ke klien kita.
async fn list_features(
&self,
request: Request<Rectangle>,
) -> Result<Response<ListFeaturesStream>, Status> {
println!("ListFeatures = {:?}", request);
let (tx, rx) = mpsc::channel(4);
let features = self.features.clone();
tokio::spawn(async move {
for feature in &features[..] {
if in_range(&feature.location().to_owned(), request.get_ref()) {
println!(" => send {feature:?}");
tx.send(Ok(feature.clone())).await.unwrap();
}
}
println!(" /// done sending");
});
let output_stream = ReceiverStream::new(rx);
Ok(Response::new(Box::pin(output_stream)))
}
Seperti yang dapat Anda lihat, kita mendapatkan objek permintaan (Rectangle tempat klien ingin menemukan Features). Kali ini, kita perlu menampilkan streaming nilai. Kita membuat saluran dan membuat tugas asinkron baru tempat kita melakukan pencarian, mengirimkan fitur yang memenuhi batasan kita ke saluran. Setengah Streaming saluran ditampilkan ke pemanggil, yang digabungkan dalam tonic::Response.
RPC streaming sisi klien: RecordRoute
Sekarang mari kita lihat sesuatu yang sedikit lebih rumit: metode streaming sisi klien RecordRoute, tempat kita mendapatkan streaming Points dari klien dan menampilkan satu RouteSummary dengan informasi tentang perjalanan mereka. Metode ini mendapatkan streaming sebagai input, yang dapat digunakan server untuk membaca dan menulis pesan. Metode ini dapat melakukan iterasi melalui pesan klien menggunakan metode next() dan menampilkan satu responsnya.
async fn record_route(
&self,
request: Request<tonic::Streaming<Point>>,
) -> Result<Response<RouteSummary>, Status> {
println!("RecordRoute");
let mut stream = request.into_inner();
let mut summary = RouteSummary::default();
let mut last_point = None;
let now = Instant::now();
while let Some(point) = stream.next().await {
let point = point?;
println!(" ==> Point = {point:?}");
// Increment the point count
summary.set_point_count(summary.point_count() + 1);
// Find features
for feature in &self.features[..] {
if feature.location().latitude() == point.latitude() {
if feature.location().longitude() == point.longitude(){
summary.set_feature_count(summary.feature_count() + 1);
}
}
}
// Calculate the distance
if let Some(ref last_point) = last_point {
let new_dist = summary.distance() + calc_distance(last_point, &point);
summary.set_distance(new_dist);
}
last_point = Some(point);
}
summary.set_elapsed_time(now.elapsed().as_secs() as i32);
Ok(Response::new(summary))
}
Dalam isi metode, kita menggunakan metode next() streaming untuk berulang kali membaca permintaan klien ke objek permintaan (dalam hal ini Point) hingga tidak ada lagi pesan. Jika ini adalah None, streaming masih bagus dan dapat terus membaca.
RPC streaming dua arah: RouteChat
Terakhir, mari kita lihat RPC streaming dua arah RouteChat().
async fn route_chat(
&self,
request: Request<tonic::Streaming<RouteNote>>,
) -> Result<Response<RouteChatStream>, Status> {
println!("RouteChat");
let mut notes: HashMap<(i32, i32), Vec<RouteNote>> = HashMap::new();
let mut stream = request.into_inner();
let output = async_stream::try_stream! {
while let Some(note) = stream.next().await {
let note = note?;
let location = note.location();
let key = (location.latitude(), location.longitude());
let location_notes = notes.entry(key).or_insert(vec![]);
location_notes.push(note);
for note in location_notes {
yield note.clone();
}
}
};
Ok(Response::new(Box::pin(output)))
}
Kali ini kita mendapatkan streaming yang, seperti dalam contoh streaming sisi klien, dapat digunakan untuk membaca dan menulis pesan. Namun, kali ini kita menampilkan nilai melalui streaming metode kita saat klien masih menulis pesan ke streaming pesannya. Sintaksis untuk membaca dan menulis di sini sangat mirip dengan metode streaming klien kita, kecuali server menampilkan RouteChatStream. Meskipun setiap sisi akan selalu mendapatkan pesan sisi lainnya dalam urutan penulisannya, baik klien maupun server dapat membaca dan menulis dalam urutan apa pun — streaming beroperasi sepenuhnya secara independen.
Kita membuat streaming output menggunakan try_stream!, yang menunjukkan bahwa streaming dapat menampilkan error.
Memulai server
Setelah mengimplementasikan metode ini, kita juga perlu memulai server gRPC agar klien dapat menggunakan layanan kita. Isi main().
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:10000".parse().unwrap();
println!("RouteGuideServer listening on: {addr}");
let route_guide = RouteGuideService {
features: load(),
};
let svc = RouteGuideServer::new(route_guide);
Server::builder().add_service(svc).serve(addr).await?;
Ok(())
}
Berikut hal yang terjadi di main(), langkah demi langkah:
- Menentukan port yang ingin kita gunakan untuk memproses permintaan klien
- Membuat
RouteGuideServicedengan fitur yang dimuat - Membuat instance server gRPC menggunakan
RouteGuideServer::new()menggunakan layanan yang kita buat. - Mendaftarkan implementasi layanan kita dengan server gRPC.
- Memanggil
serve()di server dengan detail port kita untuk melakukan tunggu pemblokiran hingga proses dihentikan.
6. Membuat klien
Di bagian ini, kita akan melihat cara membuat klien Rust untuk layanan RouteGuide di src/client/client.rs.
Pertama, masukkan kode yang dihasilkan ke dalam cakupan.
mod grpc_pb {
grpc::include_generated_proto!("generated", "routeguide");
}
use grpc_pb::route_guide_client::RouteGuideClient;
use grpc_pb::{Point, Rectangle, RouteNote};
Memanggil metode layanan
Sekarang mari kita lihat cara memanggil metode layanan kita. Di gRPC-Rust, RPC streaming bersifat asinkron dan tidak memblokir, menggunakan sintaksis async/await Rust dan streaming Tokio.
RPC streaming sisi server: PrintFeatures
Dalam RPC streaming server, klien mengirim satu pesan permintaan ke server, dan mendapatkan kembali streaming pesan respons. Di sinilah di client.rs kita memanggil metode streaming sisi server list_features() (yang sesuai dengan deklarasi rpc ListFeatures yang ditemukan di proto kita). Server, pada gilirannya, akan mengirim kembali streaming pesan Feature:
async fn print_features(client: &RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let rectangle = proto!(Rectangle {
lo: proto!(Point {
latitude: 400_000_000,
longitude: -750_000_000,
}),
hi: proto!(Point {
latitude: 420_000_000,
longitude: -730_000_000,
}),
});
let mut stream = client.list_features(rectangle).await;
while let Some(feature) = stream.recv().await {
println!(
"FEATURE: Name = \"{}\", Lat = {}, Lon = {}",
feature.name(),
feature.location().latitude(),
feature.location().longitude()
);
}
let status = stream.status().await;
assert!(status.is_ok(), "{:?}", status);
Ok(())
}
RPC streaming sisi klien: RecordRoute
Saat kita menggunakan streaming sisi klien, klien akan membuka streaming ke server dan mengirim urutan pesan. Klien akan menerima satu pesan respons saat streaming selesai.
Di sini, kita memulai panggilan dengan client.record_route().await, mengirim beberapa koordinat Point yang dihasilkan satu per satu di seluruh streaming menggunakan stream.send(point).await, lalu menutup streaming dengan stream.close_and_recv().await untuk menerima satu pesan RouteSummary server.
async fn run_record_route(client: &RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let mut rng = rand::rng();
let point_count: i32 = rng.random_range(2..100);
let mut points = vec![];
for _ in 0..=point_count {
points.push(random_point(&mut rng));
}
println!("Traversing {} points", points.len());
let mut stream = client.record_route().await;
for point in &points {
if stream.send(point).await.is_err() {
break;
}
}
match stream.close_and_recv().await {
Ok(response) => {
println!(
"SUMMARY: Feature Count = {}, Distance = {}",
response.feature_count(),
response.distance()
);
}
Err(e) => println!("something went wrong: {e:?}"),
}
Ok(())
}
RPC streaming dua arah: RouteChat
Terakhir, mari kita lihat RPC streaming dua arah RouteChat(). Di sini, klien dan server akan meneruskan urutan pesan bolak-balik. Kita membuat tugas tokio untuk terus mengirim pesan ke server dengan tx.send(note).await.is_err(). Sementara itu, rx.recv().await memproses pesan respons dari server, dan mencetaknya saat pesan tersebut masuk.
async fn run_route_chat(client: &RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let (mut tx, mut rx) = client.route_chat().await;
let start = time::Instant::now();
tokio::spawn(async move {
let mut interval = time::interval(Duration::from_millis(50));
for _ in 0..10 {
let time = interval.tick().await;
let elapsed = time.duration_since(start);
let note = proto!(RouteNote {
location: proto!(Point {
latitude: 409146138 + elapsed.as_millis() as i32,
longitude: -746188906,
}),
message: format!("at {elapsed:?}"),
});
if tx.send(note).await.is_err() {
return;
}
}
tx.close();
});
while let Some(note) = rx.recv().await {
println!(
"Note: Latitude = {}, Longitude = {}, Message = \"{}\"",
note.location().latitude(),
note.location().longitude(),
note.message()
);
}
let status = rx.status().await;
assert!(status.is_ok(), "{:?}", status);
Ok(())
}
Meskipun setiap sisi akan selalu mendapatkan pesan sisi lainnya dalam urutan penulisannya, baik klien maupun server dapat membaca dan menulis dalam urutan apa pun — streaming beroperasi sepenuhnya secara independen.
Membuat dan meneruskan klien
Untuk memanggil metode layanan, pertama-tama kita perlu membuat saluran untuk berkomunikasi dengan server. Kita membuatnya dengan membuat endpoint terlebih dahulu, menghubungkan ke endpoint tersebut, dan meneruskan saluran yang dibuat saat terhubung ke RouteGuideClient::new() sebagai berikut:
// Create channel to connect to server
let channel = Channel::builder(
"dns:///[::1]:10000",
Arc::new(LocalChannelCredentials::new()),
)
.build();
// Create a new client
let client = RouteGuideClient::new(channel);
Dengan klien ini dibuat, kita dapat memanggil metode yang kita tulis di atas, dengan meneruskan klien ke dalamnya. Kita menambahkan semua kode ini ke dalam main(), yang menggunakan runtime asinkron Tokio. Berikut kode lengkapnya:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create channel to connect to server
let channel = Channel::builder(
"dns:///[::1]:10000",
Arc::new(LocalChannelCredentials::new()),
)
.build();
// Create a new client
let client = RouteGuideClient::new(channel);
println!("\n*** SERVER STREAMING ***");
print_features(&client).await?;
println!("\n*** CLIENT STREAMING ***");
run_record_route(&client).await?;
println!("\n*** BIDIRECTIONAL STREAMING ***");
run_route_chat(&client).await?;
Ok(())
}
7. Cobalah
Untuk menjalankan klien dan server, pertama-tama pastikan kedua target biner ditentukan di Cargo.toml:
[[bin]]
name = "routeguide-server"
path = "src/server/server.rs"
[[bin]]
name = "routeguide-client"
path = "src/client/client.rs"
Kemudian, jalankan perintah berikut dari direktori kerja kita:
- Jalankan server di satu terminal:
cargo run --bin routeguide-server
- Jalankan klien dari terminal lain:
cargo run --bin routeguide-client
Anda akan melihat output seperti ini:
*** SERVER STREAMING ***
FEATURE: Name = "Patriots Path, Mendham, NJ 07945, USA", Lat = 407838351, Lon = -746143763
FEATURE: Name = "101 New Jersey 10, Whippany, NJ 07981, USA", Lat = 408122808, Lon = -743999179
FEATURE: Name = "U.S. 6, Shohola, PA 18458, USA", Lat = 413628156, Lon = -749015468
...
*** CLIENT STREAMING ***
Traversing 86 points
SUMMARY: Feature Count = 0, Distance = 803709356
*** BIDIRECTIONAL STREAMING ***
Note: Latitude = 409146138, Longitude = -746188906, Message = "at 112.45µs"
Note: Latitude = 409146139, Longitude = -746188906, Message = "at 1.00011245s"
Note: Latitude = 409146140, Longitude = -746188906, Message = "at 2.00011245s"
8. Langkah berikutnya
- Jelajahi Repositori gRPC-Rust resmi.
- Pelajari arsitektur gRPC lebih lanjut di Konsep Inti.
- Lihat dokumentasi gRPC-Rust di gRPC.io.
9. Kontributor Codelab ini
- Cathy Zhao
- Arvind Bright
- Nathaniel Ford