Go实战--Gorilla web toolkit使用之gorilla/rpc(gorilla/rpc/json)

生命不止,继续 go go go

继续Gorilla web toolkit,今天介绍rpc.

关于rpc,诸位也不会很陌生,之前也有介绍过:
Go实战–go中使用rpc(The way to go)

Go实战–golang中使用gRPC和Protobuf实现高性能api(golang/protobuf、google.golang.org/grpc)

gorilla/rpc

官网:
http://www.gorillatoolkit.org/pkg/rpc

简介:
Package gorilla/rpc is a foundation for RPC over HTTP services, providing access to the exported methods of an object through HTTP requests.

This package derives from the standard net/rpc package but uses a single HTTP request per call instead of persistent connections.

获取:

go get github.com/gorilla/rpc

API:
这里写图片描述

func NewServer

func NewServer() *Server

NewServer returns a new RPC server.

type Codec

type Codec interface { NewRequest(*http.Request) CodecRequest }

Codec creates a CodecRequest to process each request.

func (*Server) RegisterCodec

func (s *Server) RegisterCodec(codec Codec, contentType string)

RegisterCodec adds a new codec to the server.
Codecs are defined to process a given serialization scheme, e.g., JSON or XML. A codec is chosen based on the “Content-Type” header from the request, excluding the charset definition.

func (*Server) RegisterService

func (s *Server) RegisterService(receiver interface{}, name string) error

RegisterService adds a new service to the server.
The name parameter is optional: if empty it will be inferred from the receiver type name

gorilla/rpc/json

官网:
http://www.gorillatoolkit.org/pkg/rpc/json

获取:
go get github.com/gorilla/rpc/json

API:
这里写图片描述

func DecodeClientResponse

func DecodeClientResponse(r io.Reader, reply interface{}) error

DecodeClientResponse decodes the response body of a client request into the interface reply.

func EncodeClientRequest

func EncodeClientRequest(method string, args interface{}) ([]byte, error)

EncodeClientRequest encodes parameters for a JSON-RPC client request.

net/rpc

先看看golang官方为我们提供的标准库net/rpc:

  • 方法的类型是可输出的 (the method’s type is exported)
  • 方法本身也是可输出的 (the method is exported)
  • 方法必须由两个参数,必须是输出类型或者是内建类型 (the method has two arguments, both exported or builtin types)
  • 方法的第二个参数是指针类型 (the method’s second argument is a pointer)
  • 方法返回类型为 error (the method has return type error)

例子:
生成了一个Arith对象,并使用rpc.Register注册这个服务,然后通过HTTP暴露出来。
客户端可以看到服务Arith以及它的两个方法Arith.Multiply和Arith.Divide
model.go

package rpcexample

import (
    "log"
)

// Holds arguments to be passed to service Arith in RPC call
type Args struct {
    A, B int
}

// Represents 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
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
}

server/main.go

package main

import (
    "log"
    "net"
    "net/http"
    "net/rpc"

    "gorilla_toolkit/gorilla_rpc/model"
)

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)
    }
}

client/main.go

package main

import (
    "log"
    "net/rpc"

    "gorilla_toolkit/gorilla_rpc/model"
)

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)
}

gorilla/rpc应用

server/main.go

package main

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/gorilla/rpc"
    "github.com/gorilla/rpc/json"
)

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)
}

client/main.go

package main

import (
    "bytes"
    "log"
    "net/http"

    "gorilla_toolkit/gorilla_rpc/model"

    "github.com/gorilla/rpc/json"
)

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)
}

运行结果
客户端:
2018/01/05 11:50:47 2*3=6
服务端:
2018/01/05 11:50:47 Multiplying 2 with 3

这里写图片描述

本站公众号
   欢迎关注本站公众号,获取更多程序园信息
开发小院