Using PROTOBUF-RPC in the Go language

Source: Internet
Author: User
Tags mul
This is a creation in Article, where the information may have evolved or changed.

The go language version of the PROTOBUF-RPC is basically complete. Now let's simply say how to use it.

Install the test environment

Download the code first (not supported go get ):

hg clone https://bitbucket.org/chai2010/gopath

Then the downloaded directory is set to GOPATH , and added $GOPATH/bin to the PATH environment variable.

The $GOPATH/bin version under Windows is already included in the 2.4.1 protoc.exe . If you are Linux waiting for the system, please download and install the protoc program yourself.

Install protoc.exe The Go language plugin:

go install encoding/protobuf/protoc-gen-go

The plugin is based on code.google.com/p/goprotobuf/protoc-gen-go implementation, which mainly adds encoding/protobuf/protoc-gen-go/generator/service.go files for RPC the code generation. The generated RPC code relies on the net/rpc/protorpc underlying implementation of this package Protobuf-RPC , which can be used alone.

You can now run the test program:

C:\>go test net/rpc/protorpc/service.pbok      net/rpc/protorpc/service.pb     2.123s

Test pass, continue.

Compiling the Proto file

Create a pbrpc subdirectory that is named working directory and then create pbrpc/arith.pb .
net/rpc/protorpc/service.pb/service.proto pbrpc/arith.pb the subdirectory to which the files are copied.

The package name is changed arith to, arith.proto the contents of the file are as follows:

package arith;option cc_generic_services = true;option java_generic_services = true;option py_generic_services = true;message ArithRequest {    optional int32 a = 1;    optional int32 b = 2;}message ArithResponse {    optional int32 c = 1;}service ArithService {    rpc add (ArithRequest) returns (ArithResponse);    rpc mul (ArithRequest) returns (ArithResponse);    rpc div (ArithRequest) returns (ArithResponse);    rpc error (ArithRequest) returns (ArithResponse);}

The main definition is an ArithService interface. Be aware of cc_generic_services / java_generic_services , a py_generic_services few options.
I mentioned in the premise that protoc-gen-go when generating code, these 3 options must have at least one true code that will be generated RPC .

Of course, if you do not generate RPC code, you can use net/rpc/protorpc the package separately. However, protoc-gen-go the generated code is much simpler.

pbrpc/arith.pbto enter a subdirectory, compile the arith.proto file:

protoc --go_out=. arith.proto

Generate arith.pb.go the file, where RPC the code is mainly the following:

Type Arithservice Interface {ADD (in *arithrequest, out *arithresponse) error Mul (in *arithrequest, out *arithrespon SE) error Div (in *arithrequest, out *arithresponse) Error error (in *arithrequest, out *arithresponse) error}//Regis Terarithservice publish the given Arithservice implementation on the Server.func registerarithservice (SRV *rpc. Server, x arithservice) error {if err: = srv. Registername ("Arithservice", X); Err! = Nil {return err} return nil}//Servearithservice serves the given arithservice implementation on con N.func servearithservice (conn io. Readwritecloser, x Arithservice) error {srv: = RPC. NewServer () If err: = srv. Registername ("Arithservice", X); Err! = Nil {return err} srv. Servecodec (PROTORPC. NEWSERVERCODEC (conn)) return nil}//Listenandservearithservice Listen announces on the local network address laddr//an D serves the given Arithservice Implementation.func listenandservearithservice (Network, addr string, x AriThservice) Error {clients, err: = Net. Listen (Network, addr) if err! = Nil {return err} SRV: = RPC. NewServer () If err: = srv. Registername ("Arithservice", X); Err! = Nil {return err} for {conn, err: = clients. Accept () if err! = Nil {return err} go srv. Servecodec (PROTORPC. NEWSERVERCODEC (conn)} Panic ("unreachable")}type rpcarithservicestub struct {*rpc. Client}func (c *rpcarithservicestub) Add (in *arithrequest, out *arithresponse) error {return C.call ("Arithservice.add" }func (c *rpcarithservicestub) Mul (in *arithrequest, out *arithresponse) error {return C.call ("Arithservice"). Mul ", in, out)}func (c *rpcarithservicestub) Div (in *arithrequest, out *arithresponse) error {return C.call (" Arithserv Ice. Div ", in, out)}func (c *rpcarithservicestub) error (in *arithrequest, out *arithresponse) error {return C.call (" Arithse Rvice. Error ", in, out)}//Dialarithservice connects to an ArithService at the specified network Address.func dialarithservice (network, addr string) (*rpc. Client, Arithservice, error) {conn, err: = Net.  Dial (Network, addr) if err! = Nil {return nil, nil, err} c, srv: = newarithserviceclient (conn) return C, SRV, nil}//newarithserviceclient returns a Arithservice RPC. Client and stub to handle//requests to the set of Arithservice at the other end of the Connection.func NEWARITHSERVICECLI ENT (conn io. Readwritecloser) (*rpc. Client, Arithservice) {c: = RPC. Newclientwithcodec (PROTORPC. NEWCLIENTCODEC (conn)) return C, &rpcarithservicestub{c}}//Newarithservicestub returns a arithservice stub to Handl E RPC. Client.func newarithservicestub (c *rpc. Client) Arithservice {return &rpcarithservicestub{c}}

The generated server-side code is: ListenAndServeArithService , ServeArithService , RegisterArithService .
The interfaces of the generated client are:, DialArithService NewArithServiceClient NewArithServiceStub .
where RPC interfaces correspond to ArithService interfaces.

Writing test Code

Create the file in the pbrpc directory rpc_server.go , with the following code:

  Package Mainimport ("Encoding/protobuf/proto" "Errors" "./ARITH.PB") type Arith IntFunc (t *arith) Add (Args *arith. Arithrequest, reply *arith. Arithresponse) Error {reply. C = Proto. Int32 (args. Geta () + args. GETB ()) return Nil}func (t *arith) Mul (args *arith. Arithrequest, reply *arith. Arithresponse) Error {reply. C = Proto. Int32 (args. Geta () * args. GETB ()) return Nil}func (t *arith) Div (args *arith. Arithrequest, reply *arith. Arithresponse) Error {if args. GETB () = = 0 {return errors. New ("Divide by Zero")} reply. C = Proto. Int32 (args. Geta ()/args. GETB ()) return Nil}func (t *arith) Error (args *arith. Arithrequest, reply *arith. Arithresponse) error {return errors. New ("Aritherror")}func Main () {Arith. Listenandservearithservice ("TCP", ": 1234", New (Arith))}  

The key thing is arith.ListenAndServeArithService("tcp", ":1234", new(Arith)) . Of course, you can also use RegisterArithService or wait for the ServeArithService interface to be customized.

Then pbrpc create the rpc_client.go corresponding client with the following code:

Package Mainimport ("Encoding/protobuf/proto" "Log" "./ARITH.PB") func main () {//Client client, stub, err : = Arith. Dialarithservice ("TCP", "127.0.0.1:1234") if err! = Nil {log. Fatalf (' Arith. Dialarithservice ("TCP", "127.0.0.1:1234"):%v ', err)} defer client. Close () var args arith. arithrequest var reply arith. Arithresponse//Add args. A = Proto. Int32 (1) args. B = Proto. Int32 (2) If Err = stub. ADD (&args, &reply); Err! = Nil {log. Fatalf (' Arith. ADD:%v ', err)} if reply. GetC ()! = 3 {log. Fatalf (' Arith. Add:expected =%d, got =%d ', 3, reply. GetC ())}//Mul args. A = Proto. Int32 (2) args. B = Proto. Int32 (3) If Err = stub. Mul (&args, &reply); Err! = Nil {log. Fatalf (' Arith. Mul:%v ', err)} if reply. GetC ()! = 6 {log. Fatalf (' Arith. Mul:expected =%d, got =%d ', 6, reply. GetC ())}//Div args. A = Proto. Int32 (+) args. B = Proto. Int32 (5) If Err = stub. Div (&args, &reply); Err! = Nil {log. Fatalf (' Arith. Div:%v ', err)} if reply. GetC ()! = 2 {log. Fatalf (' Arith. Div:expected =%d, got =%d ', 2, reply. GetC ())}//Div zero args. A = Proto. Int32 (1) args. B = Proto. Int32 (0) If Err = stub. Div (&args, &reply); Err. Error ()! = "Divide by zero" {log. Fatalf (' Arith. error:expected =%s, got =%s ', ' divide by zero ', err. Error ())}//Error args. A = Proto. Int32 (1) args. B = Proto. Int32 (2) If Err = stub. Error (&args, &reply); Err. Error ()! = "Aritherror" {log. Fatalf (' Arith. error:expected =%s, got =%s ', "Aritherror", err. Error ())} log. Printf ("Done")}

You can then start the service and test the client.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.