转载

Go语言 RPC,json – RPC的实例

使用RPC消息传递可以实现分布式系统的设计开发。

什么是RPC:

RPC(Remote Procedure Call Protocol)—— 远程过程调用 协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。 RPC协议 假定某些 传输协议 的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI 网络通信 模型中,RPC跨越了 传输层 和 应用层 。RPC使得开发包括网络 分布式 多程序在内的应用程序更加容易。

RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

有多种 RPC模式和执行。最初由 Sun 公司提出。IETF ONC 宪章重新修订了 Sun 版本,使得 ONC RPC 协议成为 IETF 标准协议。现在使用最普遍的模式和执行是开放式软件基础的分布式计算环境(DCE)。

定义服务对象和方法:

Golang registers rpc service with an Object with a method that satisfies following conditions:

1- The method is exported. 2- The method has two arguments, both exported (or builtin) types. 3- The method's second argument is a pointer. 4- The method has return type error.

定义一个Struct:

//Represents Arith service for RPC type Arith int //Arith service has procedure Multiply which takes numbers A, B as arguments and returns error or stores product in reply func (t *Arith) Multiply(args *Args, reply *int) error {         *reply = args.A * args.B         return nil }

我们需要定义一个参数类型结构拥有参数传递给方法:

type Args struct {     A, B int }
package rpcexample  import (     "log" )  //Holds arguments to be passed to service Arith in RPC call type Args struct {     A, B int }  //Representss service Arith with method Multiply type Arith int  //Result of RPC call is of this type type Result int  //This procedure is invoked by rpc and calls rpcexample.Multiply which stores product of args.A and args.B in result pointer func (t *Arith) Multiply(args Args, result *Result) error {     return Multiply(args, result) }  //stores product of args.A and args.B in result pointer func Multiply(args Args, result *Result) error {     log.Printf("Multiplying %d with %d/n", args.A, args.B)     *result = Result(args.A * args.B)     return nil }

RPC server using Golang net/rpc package:

package main  import (     "github.com/haisum/rpcexample"     "log"     "net"     "net/http"     "net/rpc" )  func main() {     //register Arith object as a service     arith := new(rpcexample.Arith)     err := rpc.Register(arith)     if err != nil {         log.Fatalf("Format of service Arith isn't correct. %s", err)     }     rpc.HandleHTTP()     //start listening for messages on port 1234     l, e := net.Listen("tcp", ":1234")     if e != nil {         log.Fatalf("Couldn't start listening on port 1234. Error %s", e)     }     log.Println("Serving RPC handler")     err = http.Serve(l, nil)     if err != nil {         log.Fatalf("Error serving: %s", err)     } }

RPC client using Golang net/rpc

package main  import (     "github.com/haisum/rpcexample"     "log"     "net/rpc" )  func main() {     //make connection to rpc server     client, err := rpc.DialHTTP("tcp", ":1234")     if err != nil {         log.Fatalf("Error in dialing. %s", err)     }     //make arguments object     args := &rpcexample.Args{         A: 2,         B: 3,     }     //this will store returned result     var result rpcexample.Result     //call remote procedure with args     err = client.Call("Arith.Multiply", args, &result)     if err != nil {         log.Fatalf("error in Arith", err)     }     //we got our result in result     log.Printf("%d*%d=%d/n", args.A, args.B, result) }

JSON RPC server using gorilla rpc/json

Gorilla kit has rpc package to simplify default net/rpc/jsonrpc package. Slight difference form standard golang net/rpc is that it requires method signature to accept *Request object as first argument and changes Args parameter to pointer *Args.

In net/rpc our Multiply method looks like func (t *Arith) Multiply(args Args, result *Result) error . For gorilla it should look like func (t *Arith) Multiply(r *http.Request, args *Args, result *Result) error .

package main  import (     "github.com/gorilla/mux"     "github.com/gorilla/rpc"     "github.com/gorilla/rpc/json"     "log"     "net/http" )  type Args struct {     A, B int }  type Arith int  type Result int  func (t *Arith) Multiply(r *http.Request, args *Args, result *Result) error {     log.Printf("Multiplying %d with %d/n", args.A, args.B)     *result = Result(args.A * args.B)     return nil }  func main() {     s := rpc.NewServer()     s.RegisterCodec(json.NewCodec(), "application/json")     s.RegisterCodec(json.NewCodec(), "application/json;charset=UTF-8")     arith := new(Arith)     s.RegisterService(arith, "")     r := mux.NewRouter()     r.Handle("/rpc", s)     http.ListenAndServe(":1234", r) }

JSON RPC client using gorilla rpc/json

package main  import (     "bytes"     "github.com/gorilla/rpc/json"     "github.com/haisum/rpcexample"     "log"     "net/http" )  func main() {     url := "http://localhost:1234/rpc"     args := &rpcexample.Args{         A: 2,         B: 3,     }     message, err := json.EncodeClientRequest("Arith.Multiply", args)     if err != nil {         log.Fatalf("%s", err)     }     req, err := http.NewRequest("POST", url, bytes.NewBuffer(message))     if err != nil {         log.Fatalf("%s", err)     }     req.Header.Set("Content-Type", "application/json")     client := new(http.Client)     resp, err := client.Do(req)     if err != nil {         log.Fatalf("Error in sending request to %s. %s", url, err)     }     defer resp.Body.Close()      var result rpcexample.Result     err = json.DecodeClientResponse(resp.Body, &result)     if err != nil {         log.Fatalf("Couldn't decode response. %s", err)     }     log.Printf("%d*%d=%d/n", args.A, args.B, result) }

Go语言 RPC,json – RPC的实例

正文到此结束
Loading...