protorpc

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2023 License: BSD-3-Clause Imports: 10 Imported by: 0

README

protorpc

Package protorpc implements a Protobuf-RPC ClientCodec and ServerCodec for the rpc package.

Install

Install Go plugins for the protocol compiler:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

go install github.com/weiwenchen2022/protorpc/cmd/protoc-gen-go-netrpc@latest

Install protorpc package:

go get github.com/weiwenchen2022/protorpc

Examples

First, Open helloworld/helloworld.proto:

syntax = "proto3";

option go_package = "github.com/weiwenchen2022/protorpc/examples/helloworld/helloworld";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

Second, compile the helloworld.proto file, run the following command (we can use go generate to invoke this command, see helloworld.go):

protoc --go_out=. --go_opt=paths=source_relative \
	--go-netrpc_out=. --go-netrpc_opt=paths=source_relative \
	helloworld/helloworld.proto

This will regenerate the helloworld.pb.go and helloworld_netrpc.pb.go files.

Now, we can use the generated code like this:

package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/rpc"

	"github.com/weiwenchen2022/protorpc"
	pb "github.com/weiwenchen2022/protorpc/examples/helloworld/helloworld"
)

// server is used to implement helloworld.GreeterServer.
type server struct {
	pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(args *pb.HelloRequest, reply *pb.HelloReply) error {
	log.Printf("Received: %v", args.GetName())
	*reply = pb.HelloReply{Message: "Hello " + args.GetName()}
	return nil
}

func main() {
	l, e := net.Listen("tcp", ":1234")
	if e != nil {
		log.Fatal("listen error:", e)
	}

	s := rpc.NewServer()
	pb.RegisterGreeterServer(s, new(server))

	log.Printf("server listening at %v", l.Addr())
	go func() {
		for {
			conn, err := l.Accept()
			if err != nil {
				log.Fatalf("failed to accept: %v", err)
			}
			go s.ServeCodec(protorpc.NewServerCodec(conn))
		}
	}()

	conn, err := protorpc.Dial("tcp", "localhost:1234")
	if err != nil {
		log.Fatal("dialing:", err)
	}
	defer conn.Close()

	c := pb.NewGreeterClient(conn)

	// Synchronous call
	args := &pb.HelloRequest{Name: "world"}
	var reply pb.HelloReply
	err = c.SayHello(args, &reply)
	if err != nil {
		log.Fatal("greet error:", err)
	}
	fmt.Printf("Greeting: %s", reply.GetMessage())

	// Asynchronous call
	helloReply := new(pb.HelloReply)
	helloCall := c.SayHelloAsync(args, helloReply, nil)
	helloCall = <-helloCall.Done // will be equal to helloCall
	// check errors, print, etc.
}

Reference

godoc or http://godoc.org/github.com/weiwenchen2022/protorpc

Documentation

Overview

Package protorpc implements a Protobuf-RPC ClientCodec and ServerCodec for the rpc package.

Prerequisites:

  • Go, any one of the three latest major releases of Go[https://go.dev/doc/devel/release].

    For installation instructions, see Go’s Getting Started[https://go.dev/doc/install] guide.

  • Protocol buffer[https://protobuf.dev/] compiler, protoc, version 3[https://protobuf.dev/programming-guides/proto3/].

  • Go plugins for the protocol compiler:

    1. Install the protocol compiler plugins for Go using the following commands:

    $ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

    $ go install github.com/weiwenchen2022/protorpc/cmd/protoc-gen-go-grpc@latest

    2. Update your PATH so that the protoc compiler can find the plugins:

    $ export PATH="$PATH:$(go env GOPATH)/bin"

Here is a simple example. Define a service in a .proto file (helloworld/helloworld.proto):

syntax = "proto3";

option go_package = "github.com/weiwenchen2022/protorpc/examples/helloworld/helloworld";

package helloworld;

// The greeting service definition.
service Greeter {
	// Sends a greeting
	rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
	string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

Change to the example directory:

cd examples/helloworld

Run the following command:

protoc --go_out=. --go_opt=paths=source_relative \
	--go-netrpc_out=. --go-netrpc_opt=paths=source_relative \
	helloworld/helloworld.proto

This will regenerate the helloworld/helloworld.pb.go and helloworld/helloworld_netrpc.pb.go files, which contain:

  • Code for populating, serializing, and retrieving HelloRequest and HelloReply message types.
  • Generated client and server code.

The server calls (for TCP service):

package main

import (
	"fmt"
	"log"
	"net"
	"net/rpc"

	"github.com/weiwenchen2022/protorpc"
	pb "github.com/weiwenchen2022/protorpc/examples/helloworld/helloworld"
)

type server struct {
	pb.UnimplementedGreeterServer
}

func (s *server) SayHello(args *pb.HelloRequest, reply *pb.HelloReply) error {
	log.Printf("Received: %v", args.GetName())
	*reply = pb.HelloReply{Message: "Hello " + args.GetName()}
	return nil
}

func main() {
	l, e := net.Listen("tcp", ":123")
	if e != nil {
		log.Fatal("listen error:", e)
	}

	s := rpc.NewServer()
	pb.RegisterGreeterServer(s, new(server))

	log.Printf("server listening at %v", l.Addr())
	for {
		conn, err := l.Accept()
		if err != nil {
			log.Fatalf("failed to accept: %v", err)
		}
		go s.ServeCodec(protorpc.NewServerCodec(conn))
	}
}

At this point, clients can see a service "Greeter" with methods "Greeter.SayHello". To invoke one, a client first dials the server:

conn, err := protorpc.Dial("tcp", serverAddress + ":1234")
if err != nil {
	log.Fatal("dialing:", err)
}
defer conn.Close()

client := pb.NewGreeterClient(conn)

Then it can make a remote call:

// Synchronous call
args := &pb.HelloRequest{Name: "world"}
var reply pb.HelloReply
err = c.SayHello(args, &reply)
if err != nil {
	log.Fatal("greet error:", err)
}
log.Printf("Greeting: %s", reply.GetMessage())

or

// Asynchronous call
helloReply := new(pb.HelloReply)
helloCall := c.SayHelloAsync(args, helloReply, nil)
helloCall = <-helloCall.Done // will be equal to helloCall
// check errors, print, etc.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Dial

func Dial(network, address string) (*rpc.Client, error)

Dial connects to a Proto-RPC server at the specified network address.

func NewClient

func NewClient(conn io.ReadWriteCloser) *rpc.Client

NewClient returns a new rpc.Client to handle requests to the set of services at the other end of the connection.

func NewClientCodec

func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec

NewClientCodec returns a new rpc.ClientCodec using Proto-RPC on conn.

func NewServerCodec

func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec

NewServerCodec returns a new rpc.ServerCodec using Proto-RPC on conn.

func ServeConn

func ServeConn(conn io.ReadWriteCloser)

ServeConn runs the Proto-RPC server on a single connection. ServeConn blocks, serving the connection until the client hangs up. The caller typically invokes ServeConn in a go statement.

Types

This section is empty.

Directories

Path Synopsis
cmd
examples
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL