写点什么

快速搭建 Go JSON-RPC Server

2019 年 9 月 24 日

快速搭建Go JSON-RPC Server

jsonrpc 是无状态、轻量级的远程过程调用协议,传递数据格式为 JSON。GO 官方提供 rpc 包和 jsonrpc 包,与 rpc 包不同的是,jsonrpc 可以实现跨平台通信。本文将介绍如何用 Go 快速搭建一个 jsonrpc Server,用 PHP 实现 jsonrpc client 进行验证,同时也记录下验证过程中出现的坑。


实现 jsonrpc_server

引入包

1import (2    "net/rpc"3    "net"4    "log"5    "net/rpc/jsonrpc"6    "fmt"7)
复制代码


定义 server 端要伺服的 rpc method

 1// rpc handler 2type Edwin int  3// 定义rpc method 第一个参数是请求对象,第二参数是返回对象,返回值是返回rpc 内部调用过程中出现的错误信息 4func (this *Edwin) Add(args map[string]float64,res *float64) error  { 5    *res = args["num1"] + args["num2"] 6    return  nil 7} 8func (this *Edwin) Multi(args map[string]interface{},res *float64) error { 9    *res = args["num1"].(float64) * args["num2"].(float64)10    return nil11}
复制代码


注册 rpc handler,开启 server connection

 1    rpc.Register(new(Edwin)) 2 3    l,err := net.Listen("tcp",":11223") 4 5    if err!=nil{ 6        log.Fatalln("listen error:",err) 7    } 8 9    for{10        conn,err := l.Accept()1112        if err!= nil{13            log.Fatalln("accept failed:",err)14        }1516        fmt.Println("jsonrpc server  start lisen on 11223...")171819        go func(conn net.Conn) {20            fmt.Println("a new connection is coming...")21            jsonrpc.ServeConn(conn)22        }(conn)23    }
复制代码


php 实现 jsonrpc_client

 1class JsonRpc { 2    private $conn; 3 4    function __construct($host, $port) { 5        $this->conn = fsockopen($host, $port, $errno, $errStr, 2); 6 7    } 8 9    public function call($method, $params) {1011        $err = fwrite($this->conn, json_encode([12            'method' => $method,13            'params' => array($params),14            'id' => 1,15        ]));1617        if (empty($err)) {18            return false;19        }2021        stream_set_timeout($this->conn, 0, 300);2223        $line = fgets($this->conn);24        if ($line === false) {25            return NULL;26        }2728        fclose($this->conn);2930        return json_decode($line, true);31    }32}3334$client = new JsonRPC("127.0.0.1", 11223);35$client2 = new JsonRPC("127.0.0.1", 11223);36$ret = $client->Call("Edwin2.Multi", array("num1" => 14, "num2" => 20));37$ret2 = $client2->Call("Edwin2.Add", array("num1" => 14, "num2" => 20));38var_export($ret);39var_export($ret2);
复制代码


验证

 1# 开启 jsonrpc server 2go run jsonrpc_server.go 3# 正常会输出监听信息 4> jsonrpc server  start lisen on 11223... 5> a new connection is coming... 6# 执行 jsonrpc client 7php jsonrpc_clinent.php 8# 正常输出以下信息 9> array (10  'id' => 1,11  'result' => 280,12  'error' => NULL,13)array (14  'id' => 1,15  'result' => 34,16  'error' => NULL,17)
复制代码


验证中的问题

问题代码:


1$err = fwrite($this->conn, json_encode([2            'method' => $method,3            'params' => array($params),4            // 'params' => $params // 不能这么用5            'id' => 1,6        ]));
复制代码


params 参数必须用 array 包含,如果直接传递过去,将报出以下错误信息:


1array (2  'id' => 1,3  'result' => NULL,4  'error' => 'json: cannot unmarshal object into Go value of type [1]interface {}',5)
复制代码


根据 JSON-RPC 规范,参数 params 可以是 Json Array,也可以是 Json Object,可是为什么还报错呢?于是查看源码,发现:


1在 src/net/rpc/jsonrpc/server.go 第95行,go官方实现指定params必须是数组:2    var params [1]interface{}3    params[0] = x4    return json.Unmarshal(*c.req.Params, &params)5    ...
复制代码


通过这个坑发现,Go jsonrpc 并未严格按照 JSON-RPC 规范实现。


内部处理流程


作者介绍:


作者张大辉(企业代号名),目前负责贝壳找房 PHP、GO 方向研发工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/k0cQ_kIs4FhfAz_ncctRBg


2019 年 9 月 24 日 18:15877

评论 1 条评论

发布
用户头像
Go 的 net/rpc/jsonrpc 只实现了 JSON-RPC 1.0 规范,在 JSON-RPC 1.0 规范中请求的 params 只能是 JSON Array。
https://stackoverflow.com/questions/24404108/json-rpc-parameters-version-1-0-vs-2-0
2021 年 02 月 23 日 10:04
回复
没有更多了
发现更多内容

“Python的单例模式有四种写法,你知道么?”——孔乙己

BigYoung

Python 设计模式 单例模式

实战技巧,Vue原来还可以这样写

前端有的玩

Java Vue 前端 技巧

配置 SharePoint Server for Reporting Services

JackWangGeek

SharePoint

Malagu 框架的认证与授权【借鉴 Spring Security 和 aws iam 的设计】

木香丘

身份认证 权限系统

从0开始设计Flutter独立APP | 第三篇: 一劳永逸解决全局BuildContext问题

渔子长

flutter 前端 跨平台 React

【面试题系列】——Java基础

Noneplus

Java

文档写作利器:Markdown

xcbeyond

markdown

用Report Builder 创建报表

JackWangGeek

SharePoint

MySQL性能优化(一):MySQL架构与核心问题

xcbeyond

MySQL MySQL性能优化

MySQL性能优化(二):选择优化的数据类型

xcbeyond

MySQL性能优化

Excel服务

JackWangGeek

SharePoint

Malagu 框架开发 React 应用新体验

木香丘

Serverless React 微前端 微应用 Malagu

API接口设计最佳实践

Man

Java 安全开发 设计实践 APi设计 接口管理

PowerPivot服务

JackWangGeek

SharePoint

计算机网络基础(二)---网络层-IP协议详解

书旅

php laravel 计算机网络 网络协议

Visio服务

JackWangGeek

SharePoint

doris临时故障恢复过程时序图

刘志刚

一致性协议算法

张瑞浩

【进收藏夹吃灰系列】——Java基础快速扫盲

Noneplus

Java

第六周总结

石刻掌纹

MySQL性能优化(三):深入理解索引的这点事

xcbeyond

MySQL 索引 MySQL性能优化

Spring配置类深度剖析-总结篇(手绘流程图,可白嫖)

YourBatman

spring springboot @Configuration 白嫖

架构师训练营作业 -- Week 6

吴炳华

极客大学架构师训练营

CAP原理

李白

那些年,我在阿里当数据开发

DeeperMan

大数据

震惊!ConcurrentHashMap里面也有死循环,作者留下的“彩蛋”了解一下?

why技术

Java 源码 jdk 后端 bug

昨天、今天、明天

escray

SQL Server 报表服务

JackWangGeek

SharePoint

PerformancePoint服务

JackWangGeek

SharePoint

PerformancePoint 组件概述

JackWangGeek

SharePoint Online

Doris 临时失效处理过程

石刻掌纹

2021年全国大学生计算机系统能力大赛操作系统设计赛 技术报告会

2021年全国大学生计算机系统能力大赛操作系统设计赛 技术报告会

快速搭建Go JSON-RPC Server-InfoQ