百木园-与人分享,
就是让自己快乐。

golang的jsonrpc客户端通用写法

服务端

package main

import (
	\"errors\"
	\"fmt\"
	\"log\"
	\"net\"
	\"net/rpc\"
	\"net/rpc/jsonrpc\"
	\"os\"
)

// 算数运算结构体
type Arith struct {
}

// 算数运算请求结构体
type ArithRequest struct {
	A int
	B int
}

// 算数运算响应结构体
type ArithResponse struct {
	Pro int // 乘积
	Quo int // 商
	Rem int // 余数
}

// 乘法运算方法
func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
	res.Pro = req.A * req.B
	return nil
}

// 除法运算方法
func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error {
	if req.B == 0 {
		return errors.New(\"divide by zero\")
	}
	res.Quo = req.A / req.B
	res.Rem = req.A % req.B
	return nil
}

func main() {
	rpc.Register(new(Arith)) // 注册rpc服务

	lis, err := net.Listen(\"tcp\", \"127.0.0.1:8096\")
	if err != nil {
		log.Fatalln(\"fatal error: \", err)
	}

	fmt.Fprintf(os.Stdout, \"%s\", \"start connection\")

	for {
		conn, err := lis.Accept() // 接收客户端连接请求
		if err != nil {
			continue
		}

		go func(conn net.Conn) { // 并发处理客户端请求
			fmt.Fprintf(os.Stdout, \"%s\", \"new client in coming\\n\")
			jsonrpc.ServeConn(conn)
		}(conn)
	}
}

go标准库客户端

package main

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

// 算数运算请求结构体
type ArithRequest struct {
	A int
	B int
}

// 算数运算响应结构体
type ArithResponse struct {
	Pro int // 乘积
	Quo int // 商
	Rem int // 余数
}

func main() {
	conn, err := jsonrpc.Dial(\"tcp\", \"127.0.0.1:8096\")
	if err != nil {
		log.Fatalln(\"dailing error: \", err)
	}

	req := ArithRequest{9, 2}
	var res ArithResponse

	err = conn.Call(\"Arith.Multiply\", req, &res) // 乘法运算
	if err != nil {
		log.Fatalln(\"arith error: \", err)
	}
	fmt.Printf(\"%d * %d = %d\\n\", req.A, req.B, res.Pro)

	err = conn.Call(\"Arith.Divide\", req, &res)
	if err != nil {
		log.Fatalln(\"arith error: \", err)
	}
	fmt.Printf(\"%d / %d, quo is %d, rem is %d\\n\", req.A, req.B, res.Quo, res.Rem)
}

通用客户端

主要是下面这种方式,其他任何语言都可以使用tcp封装入参和并且解析返回数据,因为入参和返回值都可以通过json进行解析

package main

import (
	\"bytes\"
	\"encoding/json\"
	\"fmt\"
	\"io\"
	\"net\"
)

func main() {
	err := f()
	if err != nil {
		panic(err)
	}
}

func f() error {
	c, err := net.Dial(\"tcp\", \"127.0.0.1:8096\")
	if err != nil {
		return err
	}
	defer c.Close()

	type clientRequest struct {
		Method string `json:\"method\"`
		Params [1]any `json:\"params\"` // 参数就是服务器结构体序列化的json
		Id     uint64 `json:\"id\"`
	}

	var b bytes.Buffer
	err = json.NewEncoder(io.MultiWriter(c, &b)).Encode(clientRequest{
		Method: \"Arith.Divide\",
		Params: [1]any{json.RawMessage(`{\"A\":123,\"B\":17}`)},
		Id:     1,
	})
	if err != nil {
		return err
	}
	fmt.Println(\"args\", b.String())

	var clientResponse struct {
		Id     uint64           `json:\"id\"`
		Result *json.RawMessage `json:\"result\"` // 返回结果就是服务器结果结构体
		Error  any              `json:\"error\"`
	}

	b.Reset()
	err = json.NewDecoder(io.TeeReader(c, &b)).Decode(&clientResponse)
	if err != nil {
		return err
	}
	fmt.Println(\"resp\", b.String())

	var ArithResponse struct {
		Pro int // 乘积
		Quo int // 商
		Rem int // 余数
	}
	err = json.Unmarshal(*clientResponse.Result, &ArithResponse)
	if err != nil {
		return err
	}

	fmt.Println(ArithResponse)
	return nil
}

可以看到结果是:

args {\"method\":\"Arith.Divide\",\"params\":[{\"A\":123,\"B\":17}],\"id\":1}
resp {\"id\":1,\"result\":{\"Pro\":0,\"Quo\":7,\"Rem\":4},\"error\":null}
{0 7 4}

因此用telnet就可以做到与服务器通信,所以客户端可以是其他任何语言,只要能收发tcp即可

image

.qm_point{color:#6DA47D;font-size:18px}.qm_a{color:#0000FF}
作者:janbar
出处:https://www.cnblogs.com/janbar
本文版权归作者和博客园所有,欢迎转载,转载请标明出处。喜欢我的文章请 [关注我] 吧。
如果您觉得本篇博文对您有所收获,可点击 [推荐] [收藏] ,或到右侧 [打赏] 里请我喝杯咖啡,非常感谢。


来源:https://www.cnblogs.com/janbar/p/16942513.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » golang的jsonrpc客户端通用写法