rpc 全称 Remote Procedure Call 远程过程调用,即调用远程方法。我们调用当前进程中的方法时很简单,但是想要调用不同进程,甚至不同主机、不同语言中的方法时就需要借助 rpc 来实现,下面我一步步实现一个简单的 rpc 调用。

server 端注册函数,运行并接收客户端请求

  1. func main() {
  2. srv := NewServer()
  3. srv.Register("fn", fn)
  4. srv.Run()
  5. }
  6. //为了简单,这里只需要接收到消息打印出就代表执行成功
  7. func fn(args ...interface{}) {
  8. fmt.println(args)
  9. }

定义请求格式

  1. type rpcData struct {
  2. Name string //函数名
  3. Args []interface{} //参数
  4. }

server 运行起来后,接收 socket 请求,解析消息调用已注册的函数

  1. //server结构体
  2. type server struct {
  3. conn net.Conn //socket连接
  4. maps map[string]reflect.Value //函数字典
  5. }
  6. //构造函数
  7. func NewServer() *server {
  8. return &server{
  9. maps: make(map[string]reflect.Value),
  10. }
  11. }
  12. //注册函数
  13. func (s *server) Register(fname string, fun interface{}) {
  14. if _, ok := s.maps[fname]; !ok {
  15. s.maps[fname] = reflect.ValueOf(fun)
  16. }
  17. }
  18. //运行一个socket接收请求
  19. func (s *server) Run() {
  20. listen, err := net.Listen("tcp4", ":3001")
  21. if err != nil {
  22. panic(err)
  23. }
  24. for {
  25. s.conn, err = listen.Accept()
  26. if err != nil {
  27. continue
  28. }
  29. go s.handleConnect()
  30. }
  31. }

处理请求时,这里为了简单我使用 json 解析,同时需要定义一个简单的协议:客户端发送时,前4个字节放置消息长度,这样服务端接收到时就能知道消息的长度,从而正常解码消息

  1. func (s *server) handleConnect() {
  2. for {
  3. header := make([]byte, 4)
  4. if _, err := s.conn.Read(header); err != nil {
  5. continue
  6. }
  7. bodyLen := binary.BigEndian.Uint32(header)
  8. body := make([]byte, int(bodyLen))
  9. if _, err := s.conn.Read(body); err != nil {
  10. continue
  11. }
  12. var req rpcData
  13. if err := json.Unmarshal(body, &req); err != nil {
  14. continue
  15. }
  16. inArgs := make([]reflect.Value, len(req.Args))
  17. for i := range req.Args {
  18. inArgs[i] = reflect.ValueOf(req.Args[i])
  19. }
  20. fn := s.maps[req.Name]
  21. fn.Call(inArgs)
  22. }
  23. }

client 端只需调用函数,通过网络发送请求

  1. func main() {
  2. var req = rpcData{"fn", []interface{}{1, "aaa"}}
  3. rpcCall(req)
  4. }
  5. func rpcCall(data rpcData) {
  6. conn, err := net.Dial("tcp4", "127.0.0.1:3001")
  7. if err != nil {
  8. panic(err)
  9. }
  10. req, err := json.Marshal(data)
  11. if err != nil {
  12. panic(err)
  13. }
  14. buf := make([]byte, 4+len(req))
  15. binary.BigEndian.PutUint32(buf[:4], uint32(len(req)))
  16. copy(buf[4:], req)
  17. _, err = conn.Write(buf)
  18. if err != nil {
  19. panic(err)
  20. }
  21. }

测试时,首先运行 server,然后运行 client,只要看到正确的打印就代表调用成功,这就是一个最简单(简陋)的 rpc 了。

当我们使用 grpc 这些 rpc 框架时,就可以不用自己实现消息编码解码、socket连接这些细节,专注于业务逻辑,而且更为可靠。

参考: https://github.com/ankur-anand/simple-go-rpc

动手实现一个简单的 rpc 框架到入门 grpc (上)的更多相关文章

  1. 动手实现一个简单的 rpc 框架到入门 grpc (下)

    之前手动实现了一次简陋的 rpc 调用,为了简单使用了 json 编码信息,其实这是非常不可靠的,go 中 json 解析会有一些问题,比如整数会变成浮点数,而且 json 字符串比较占空间. gRP ...

  2. 徒手撸一个简单的RPC框架

    来源:https://juejin.im/post/5c4481a4f265da613438aec3 之前在牛逼哄哄的 RPC 框架,底层到底什么原理得知了RPC(远程过程调用)简单来说就是调用远程的 ...

  3. 动手写一个简单的Web框架(模板渲染)

    动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...

  4. 动手写一个简单的Web框架(Werkzeug路由问题)

    动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...

  5. 动手写一个简单的Web框架(HelloWorld的实现)

    动手写一个简单的Web框架(HelloWorld的实现) 关于python的wsgi问题可以看这篇博客 我就不具体阐述了,简单来说,wsgi标准需要我们提供一个可以被调用的python程序,可以实函数 ...

  6. 自己动手写一个简单的MVC框架(第一版)

    一.MVC概念回顾 路由(Route).控制器(Controller).行为(Action).模型(Model).视图(View) 用一句简单地话来描述以上关键点: 路由(Route)就相当于一个公司 ...

  7. 一个简单的"RPC框架"代码分析

    0,服务接口定义---Echo.java /* * 定义了服务器提供的服务类型 */ public interface Echo { public String echo(String string) ...

  8. 自己动手写一个简单的MVC框架(第二版)

    一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在这个System.W ...

  9. 一个简单的RPC框架

    一个 系统模型 二.数据库代码实现 1. mkdir database cd database vim dbInit.c /* * * Database Init tool * */ #include ...

随机推荐

  1. EasyARM-iMX257 linux两年前的笔记

    我依然清晰的记得刚拿到Imx283 257的情景,兴奋中充满忧虑,对操作系统的概念只知一二,不知三四!!周立功出品的资料我一直觉得是比较精品的,同样这款iMX283配套的文档资料(v1.04)也是比较 ...

  2. 快速升级Zabbix 5.0 版本

    Zabbix 5.0 增加了很多新功能,如:垂直菜单.隐藏菜单.用户界面中的测试项目.限制代理检查.查找并替换预处理步骤 ES7支持等等...快来部署体验一把尝鲜体验 Zabbix 5.0 吧     ...

  3. 安装apoc插件

    APOC是Neo4j 3.3版本推出时推荐的一个Java存储过程包,包含丰富的函数和存储过程,作为对Cypher所不能提供的复杂图算法和数据操作功能的补充,APOC还具有使用灵活.高性能等优势. 1. ...

  4. void out2() const{

    include "stdafx.h" include using namespace std; class aa{ int num; public: aa(){ int b =10 ...

  5. filebeat v6.3 如何增加ip 字段

    我们知道filebeat获取数据之后是会自动获取主机名的,项目上有需要filebeat送数据的时候送一个ip字段出来 方法:配置filebeat配置文件 解释一下:field 是字段模块 在这个模块下 ...

  6. Fibonacci(模板)【矩阵快速幂】

    Fibonacci 题目链接(点击) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20989   Accepted: 14 ...

  7. CSS基础之简单介绍

    网页诞生初期,没有描述样式的语言,创建了很多用于描述样式的标签.但这些标签破坏了html作为一门结构语言的表现. 于是,W3C在1995年开始起草CSS,提出将结构和样式分离的解决方案. 元素 元素是 ...

  8. 网易java高级开发课程 面对上亿数据量,网易用啥技术?

  9. 安装Centos 7 并且配置远程登录

    安装: 1.安装VMware fusion.https://www.vmware.com/cn/products/fusion/fusion-evaluation.html 2.下载centos 7 ...

  10. swift对象存储安装

    对象存储服务概览 OpenStack对象存储是一个多租户的对象存储系统,它支持大规模扩展,可以以低成本来管理大型的非结构化数据,通过RESTful HTTP 应用程序接口. 它包含下列组件: 代理服务 ...