# 安装

go get -u github.com/sunquakes/jsonrpc4go

# 开始使用

  • 服务端代码
package main

import (
	"github.com/sunquakes/jsonrpc4go"
)

type IntRpc struct{}

type Params struct {
	A int `json:"a"`
	B int `json:"b"`
}

func (i *IntRpc) Add(params *Params, result *int) error {
	a := params.A + params.B
	*result = interface{}(a).(int)
	return nil
}

func main() {
	s, _ := jsonrpc4go.NewServer("http", 3232) // http协议
	s.Register(new(IntRpc))
	s.Start()
}
  • 客户端代码
package main

import (
	"fmt"
	"github.com/sunquakes/jsonrpc4go"
)

type Params struct {
	A int `json:"a"`
	B int `json:"b"`
}

func main() {
	result := new(int)
	c, _ := jsonrpc4go.NewClient("IntRpc", "http", "127.0.0.1:3232") // http协议
	err := c.Call("Add", Params{1, 6}, result, false)
	// 发送的数据格式: {"id":"1604283212", "jsonrpc":"2.0", "method":"IntRpc/Add", "params":{"a":1,"b":6}}
	// 接收的数据格式: {"id":"1604283212", "jsonrpc":"2.0", "result":7}
	fmt.Println(err)     // nil
	fmt.Println(*result) // 7
}

# 路由

# 规则

路由由3部分组成,第一部分是struct名,中间是分隔符/,最后是struct的方法名。

# 如何定义服务的路由

  • 声明一个struct,名为IntRpc
package main

type IntRpc struct{}
  • 声明struct的方法Add
package main

func (i *IntRpc) Add(params *Params, result *int) error {
	a := params.A + params.B
	*result = interface{}(a).(int)
	return nil
}
  • 启动服务端并注册struct后,可以通过new一个客户端去请求服务端,每个客户端映射一个服务
c, _ := jsonrpc4go.NewClient("IntRpc", "http", "127.0.0.1:3232") // 第一个参数是struct名
err := c.Call("Add", Params{1, 6}, result, false) // 第一个参数是struct的方法名
  • 客户端请求服务端的数据
{
  "id": "1604283212",
  "jsonrpc": "2.0",
  "method": "IntRpc/Add",
  "params": {
    "a": 1,
    "b": 6
  }
}
  • 服务端响应客户端的数据
{
  "id": "1604283212",
  "jsonrpc": "2.0",
  "result": 7
}

# 更多特性

  • tcp协议
s, _ := jsonrpc4go.NewServer("tcp", 3232) // tcp协议

c, _ := jsonrpc4go.NewClient("IntRpc", "tcp", "127.0.0.1:3232") // tcp协议
  • 钩子 (在代码's.Start()'前添加下面的代码)
// 在方法前执行的钩子方法
s.SetBeforeFunc(func (id interface{}, method string, params interface{}) error {
// 如果方法返回error类型,服务端停止执行并返回错误信息到客户端
// 例:return errors.New("Custom Error")
return nil
})
// 在方法后执行的钩子方法
s.SetAfterFunc(func (id interface{}, method string, result interface{}) error {
// 如果方法返回error类型,服务端停止执行并返回错误信息到客户端
// 例:return errors.New("Custom Error")
return nil
})
  • 限流 (在代码's.Start()'前添加下面的代码)
s.SetRateLimit(20, 10) // 最大并发数为10, 最大请求数为每秒20个
  • tcp协议时自定义请求结束符
// 在代码's.Start()'前添加下面的代码
s.SetOptions(server.TcpOptions{"aaaaaa", nil}) // 仅tcp协议生效
// 在代码'c.Call()'或'c.BatchCall()'前添加下面的代码
c.SetOptions(client.TcpOptions{"aaaaaa", nil}) // 仅tcp协议生效
  • 通知请求
// 通知
result2 := new(Result2)
err2 := c.Call("Add2", Params{1, 6}, result2, true)
// 发送的数据格式: {"jsonrpc":"2.0","method":"IntRpc/Add2","params":{"a":1,"b":6}}
// 接收的数据格式: {"jsonrpc":"2.0","result":{"c":7}}
fmt.Println(err2) // nil
fmt.Println(*result2) // {7}
  • 批量请求
// 批量请求
result3 := new(int)
err3 := c.BatchAppend("Add1", Params{1, 6}, result3, false)
result4 := new(int)
err4 := c.BatchAppend("Add", Params{2, 3}, result4, false)
c.BatchCall()
// 发送的数据格式: [{"id":"1604283212","jsonrpc":"2.0","method":"IntRpc/Add1","params":{"a":1,"b":6}},{"id":"1604283212","jsonrpc":"2.0","method":"IntRpc/Add","params":{"a":2,"b":3}}]
// 接收的数据格式: [{"id":"1604283212","jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found","data":null}},{"id":"1604283212","jsonrpc":"2.0","result":5}]
fmt.Println((*err3).Error()) // Method not found
fmt.Println(*result3) // 0
fmt.Println(*err4)    // nil
fmt.Println(*result4) // 5
  • 用户端负载均衡
c, _ := jsonrpc4go.NewClient("IntRpc", "tcp", "127.0.0.1:3232,127.0.0.1:3233,127.0.0.1:3234")

# 服务注册和发现

# Consul

/**
 * check: true或者false, 开启健康检查
 * interval: 健康检查周期,例:10s
 * timeout: 请求超时时间,例:10s
 * instanceId: 实例ID,同一服务多负载时区分用,例:1
 */
dc, _ := consul.NewConsul("http://localhost:8500?check=true&instanceId=1&interval=10s&timeout=10s")

// 在服务端设置,如果使用默认的节点ip 
s, _ := jsonrpc4go.NewServer("tcp", 3614)
// hostname如果为"",则会自动获取当前节点ip注册
s.SetDiscovery(dc, "127.0.0.1")
s.Register(new(IntRpc))
s.Start()

// 在客户端设置
c, _ := jsonrpc4go.NewClient("IntRpc", "tcp", dc)

# Nacos

dc, _ := nacos.NewNacos("http://127.0.0.1:8849")

// 在服务端设置,如果使用默认的节点ip 
s, _ := jsonrpc4go.NewServer("tcp", 3616)
// hostname如果为"",则会自动获取当前节点ip注册
s.SetDiscovery(dc, "127.0.0.1")
s.Register(new(IntRpc))
s.Start()

// 在客户端设置
c, _ := jsonrpc4go.NewClient("IntRpc", "tcp", dc)