当前位置: 首页 > 工具软件 > JSON-RPC > 使用案例 >

golang之jsonrpc

堵雅健
2023-12-01

rpc, 个人理解就是调用不在一个机器上的方法。
jsonrpc就是调用过程中使用json格式的数据通信。

golang对jsonrpc有相应的标准库支持,记录一下如何使用。

代码结构

测试代码结构(请根据自己实际目录调整):

[root@gl jsonrpc]# tree
.
├── client
│   └── client.go
├── main.go
└── server
    ├── calc.go
    └── cmd
        └── main.go

服务端

calc.go:

package server

import (
	"fmt"
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

type Calc struct{}

type Args struct {
	A  float64 `json:"a"`
	B  float64 `json:"b"`
	Op string  `json:"op"`
}

type Reply struct {
	Msg  string  `json:"msg"`
	Data float64 `json:"data"`
}

// func (t *T) MethodName(argType T1, replyType *T2) error
// 一定要满足这种格式, 其中replyType要为指针。并注意大小写
func (c *Calc) Compute(args Args, reply *Reply) error {
	var (
		msg string = "ok"
	)

	switch args.Op {
	case "+":
		reply.Data = args.A + args.B
	case "-":
		reply.Data = args.A - args.B
	case "*":
		reply.Data = args.A * args.B
	case "/":
		if args.B == 0 {
			msg = "in divide op, B can't be zero"
		} else {
			reply.Data = args.A / args.B
		}
	default:
		msg = fmt.Sprintf("unsupported op:%s", args.Op)
	}
	reply.Msg = msg

	if reply.Msg == "ok" {
		return nil
	}
	return fmt.Errorf(msg)
}

// 启动server端
func Start() {
	err := rpc.Register(new(Calc))

	if err != nil {
		panic(err)
	}

	listener, err := net.Listen("tcp", "127.0.0.1:8888")
	if err != nil {
		panic(err)
	}

	for {
		conn, err := listener.Accept()

		if err != nil {
			log.Println(err)
			continue
		}

		go jsonrpc.ServeConn(conn)
	}
}

server/cmd/main.go:

package main

// 具体情况要调整这里的路径
import "gerrylon.top/learnGo/jsonrpc/server"

func main() {
	server.Start()
}

客户端

client.go(这个只是做了一个封装,方便调用):

package client

import (
	"fmt"
	"gerrylon.top/learnGo/jsonrpc/server"
	"log"
	"net/rpc/jsonrpc"
)

func Call(args server.Args, reply *server.Reply) error {
	conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8888")
	if err != nil {
		log.Fatalln("dailing error: ", err)
		return err
	}

	defer conn.Close()

    // 调用远程的Calc的Compute方法
	err = conn.Call("Calc.Compute", args, &reply)
	return err 
}

main.go:

package main

import (
	"fmt"
	"gerrylon.top/learnGo/jsonrpc/client"
	"gerrylon.top/learnGo/jsonrpc/server"
)

func main() {
	args := server.Args{
		A:  1,
		B:  2,
		Op: "+",
	}

	var reply server.Reply

	err := client.Call(args, &reply)
	display(err, args, reply)

	args = server.Args{
		A: 1, B: 0, Op: "/",
	}
	err = client.Call(args, &reply)
	display(err, args, reply)
}

func display(err error, args server.Args, reply server.Reply) {
	if err != nil {
		fmt.Printf("err:%v\n", err)
	} else {
		// 如果err不为nil,这里的reply是上个调用的值
		// 因此可能会出现1.00 / 0.00=3.00
		fmt.Printf("%.2f %s %.2f=%.2f\n", args.A, args.Op, args.B, reply.Data)
	}
}

输出:

1.00 + 2.00=3.00
err:in divide op, B can’t be zero

总结

  • 远程方法一定要符合func (t *T) MethodName(argType T1, replyType *T2) error这种格式
  • 对调用返回的错误一定要处理

参考:
https://www.jianshu.com/p/98a84a6339b7

欢迎补充指正!

 类似资料: