On this page
Apoya este blog
Si te resulta util este contenido, considera apoyar el blog.

Introducción#
En este artículo exploraremos gRPC con una aplicación sencilla de ping, básicamente realizaremos un ping y mediremos el tiempo que toma para que el mensaje vaya al servidor y regrese antes de reportarlo en la terminal. Puedes encontrar el código fuente aquí.
Protobuf#
Como probablemente ya sepas, gRPC serializa datos utilizando protocol buffers. Vamos a crear un RPC Unario de la siguiente manera.
syntax = "proto3";
service PingService {
rpc Ping (PingRequest) returns (PingResponse);
}
message PingRequest {
string data = 1;
}
message PingResponse {
string data = 1;
}
Con este archivo estamos definiendo un servicio que será capaz de enviar una única PingRequest y obtener una única PingResponse. Tenemos un campo Data que va y viene para enviar algunos bytes por la red (aunque no nos importe mucho, podría ser importante o crucial en una prueba de rendimiento).
Generando el código#
Para poder utilizar protobuf necesitamos generar el código para la aplicación que estamos escribiendo, en este caso para golang, el comando sería el siguiente:
protoc -I ping/ ping/ping.proto --go_out=plugins=grpc:ping
Esto nos dará una definición del servicio y las estructuras necesarias para manejar los datos que hemos definido como mensajes.
Cliente#
El cliente realiza la mayor parte del trabajo aquí. Como puedes ver, puedes suministrar 2 argumentos: uno para apuntar a otro host:puerto y el segundo para enviar una cadena de texto a tu gusto. Luego mide el tiempo que tarda en enviar y recibir el mensaje de vuelta, y lo imprime en la pantalla con una línea similar a la del comando ping real en Linux.
package main
import (
"context"
"log"
"os"
"time"
pb "github.com/kainlite/grpc-ping/ping"
"google.golang.org/grpc"
)
const (
defaultAddress = "localhost:50000"
defaultData = "00"
)
func main() {
data := defaultData
address := defaultAddress
if len(os.Args) > 2 {
address = os.Args[1]
data = os.Args[2]
}
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewPingServiceClient(conn)
index := 0
for {
trip_time := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.Ping(ctx, &pb.PingRequest{Data: data})
if err != nil {
log.Fatalf("could not connect to: %v", err)
}
log.Printf("%d characters roundtrip to (%s): seq=%d time=%s", len(r.Data), address, index, time.Since(trip_time))
time.Sleep(1 * time.Second)
index++
}
}
Servidor#
El servidor es simplemente un servidor de eco, ya que enviará de vuelta cualquier cosa que le envíes y lo registrará en la consola. De manera predeterminada, escuchará en el puerto 50000.
package main
import (
"context"
"log"
"net"
pb "github.com/kainlite/grpc-ping/ping"
"google.golang.org/grpc"
)
const (
port = ":50000"
)
// server is used to implement ping.PingServer.
type server struct{}
// Ping implements ping.PingServer
func (s *server) Ping(ctx context.Context, in *pb.PingRequest) (*pb.PingResponse, error) {
log.Printf("Received: %v", in.Data)
return &pb.PingResponse{Data: "Data: " + in.Data}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterPingServiceServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
Probándolo#
Ping regular#
$ ping localhost -c 4
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.145 ms
64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.152 ms
64 bytes from localhost (::1): icmp_seq=3 ttl=64 time=0.154 ms
64 bytes from localhost (::1): icmp_seq=4 ttl=64 time=0.141 ms
--- localhost ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3144ms
rtt min/avg/max/mdev = 0.141/0.148/0.154/0.005 ms
Cliente#
Esto es lo que veríamos en la terminal mientras lo probamos.
$ go run ping_client/main.go
2019/06/23 18:01:02 8 characters roundtrip to (localhost:50000): seq=0 time=1.941841ms
2019/06/23 18:01:03 8 characters roundtrip to (localhost:50000): seq=1 time=420.992µs
2019/06/23 18:01:04 8 characters roundtrip to (localhost:50000): seq=2 time=401.115µs
2019/06/23 18:01:05 8 characters roundtrip to (localhost:50000): seq=3 time=428.467µs
2019/06/23 18:01:06 8 characters roundtrip to (localhost:50000): seq=4 time=374.057µs
Como puedes ver, la conexión inicial toma un poco más de tiempo, pero después de eso el tiempo de ida y vuelta es muy consistente (por supuesto, nuestro simple ping no cubre errores, pérdida de paquetes, etc.).
Servidor#
El servidor solo hace eco de lo que recibe y lo registra en la consola.
$ go run ping_server/main.go
2019/06/23 18:01:02 Received: 00
2019/06/23 18:01:03 Received: 00
2019/06/23 18:01:04 Received: 00
2019/06/23 18:01:05 Received: 00
2019/06/23 18:01:06 Received: 00
Notas finales#
Como puedes ver, gRPC es bastante rápido y simplifica mucho todo lo que necesitas hacer para tener un sistema de mensajería altamente eficiente o una comunicación entre microservicios, por ejemplo. También es fácil generar el código base para cualquier lenguaje que prefieras y tener una interfaz común que todos deben aceptar.
Errata#
Si encuentras algún error o tienes alguna sugerencia, por favor envíame un mensaje para que se corrija.
$ Comentarios
Online: 0Por favor inicie sesión para poder escribir comentarios.