golang的jsonrpc客户端通用写法
服务端
copypackage 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标准库客户端
copypackage 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进行解析
copypackage 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
}
可以看到结果是:
copyargs {"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即可
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10亿数据,如何做迁移?
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 易语言 —— 开山篇
· Trae初体验