说明

本文的目的

  • 理解一下rpc协议使用上的区别
  • golang下jsonrpc框架的使用

示例

定义RPC协议

import "github.com/pkg/errors"

//定义一个叫做Demo的Rpc服务协议
//包含参数结构和2个不同的参数处理协议
// 返回值通过result指针获取,这点是由RPC服务来定义的
type DemoService struct {
}

//包含1: 参数的个数和类型
type Args struct {
	A, B int
}

//包含2: 参数的处理协议 除法协议
func (DemoService) Div(args Args, result *float64) error {
	if args.B == 0 {
		return errors.New("divide by zero")
	}

	*result = float64(args.A) / float64(args.B)

	return nil
}

//包含2: 参数的处理协议 乘法协议
func (DemoService) Muti(args Args, result *int) error {

	*result = args.A * args.B

	return nil
}

注册为服务端

package main

import (
	"fmt"
	"learning_go/rpc/demorpc"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

func main() {

	//注册demoService到rpc框架中,成为当前server的rpc协议之一
	rpc.Register(demorpc.DemoService{})

	listen, err := net.Listen("tcp", ":9999")
	if err!=nil{
		panic(err)
	}

	for  {

		conn, err := listen.Accept()

		if err!=nil{
			fmt.Println("Server listens error")
			continue
		}

		go jsonrpc.ServeConn(conn)

	}
}



客户端测试

通过telnet测试

telent localhost 9999 链接上后如初参数


"method":"DemoService.Div","params":[{"A":3,"B":4}],"id":1}
=》{"id":1,"result":0.75,"error":null}
{"method":"DemoService.Muti","params":[{"A":3,"B":4}],"id":1}
=>{"id":1,"result":12,"error":null}

说明不同的参数可以调用不同的协议

注意:虽然服务器启动了端口,但是不能通过接口调用,因为接口使用的http协议,会包含http的头部和body,数据格式不符合我们定义的rpc协议

通过客户端测试

package main

import (
	"fmt"
	"learning_go/rpc/demorpc"
	"net"
	"net/rpc/jsonrpc"
)

func main() {
	conn, err := net.Dial("tcp",":9999")

	if err!=nil{
		panic(err)
	}

	var result1 float64
	var result2 int
	client := jsonrpc.NewClient(conn)


	//调用除法
	err = client.Call("DemoService.Div",
		demorpc.Args{
			A: 3,
			B: 4,
		}, &result1)

	fmt.Println(result1,err)


	//调用乘法
	err = client.Call("DemoService.Muti",
		demorpc.Args{
			A: 3,
			B: 4,
		}, &result2)

	fmt.Println(result2,err)
}

结论

  1. 可以自定义server的协议参数和协议动作
  2. 注册到jsonrpc框架后,可以借助框架实现服务间的rpc调用
  3. rpc基于自定义协议,而http基于http协议,两者主要在于协议不同
  4. 协议的本质就是数据交换格式