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

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

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

定义请求格式

type rpcData struct {
Name string //函数名
Args []interface{} //参数
}

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

//server结构体
type server struct {
conn net.Conn //socket连接
maps map[string]reflect.Value //函数字典
}
//构造函数
func NewServer() *server {
return &server{
maps: make(map[string]reflect.Value),
}
}
//注册函数
func (s *server) Register(fname string, fun interface{}) {
if _, ok := s.maps[fname]; !ok {
s.maps[fname] = reflect.ValueOf(fun)
}
}
//运行一个socket接收请求
func (s *server) Run() {
listen, err := net.Listen("tcp4", ":3001")
if err != nil {
panic(err)
}
for {
s.conn, err = listen.Accept()
if err != nil {
continue
}
go s.handleConnect()
}
}

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

func (s *server) handleConnect() {
for {
header := make([]byte, 4)
if _, err := s.conn.Read(header); err != nil {
continue
}
bodyLen := binary.BigEndian.Uint32(header)
body := make([]byte, int(bodyLen))
if _, err := s.conn.Read(body); err != nil {
continue
}
var req rpcData
if err := json.Unmarshal(body, &req); err != nil {
continue
}
inArgs := make([]reflect.Value, len(req.Args))
for i := range req.Args {
inArgs[i] = reflect.ValueOf(req.Args[i])
}
fn := s.maps[req.Name]
fn.Call(inArgs)
}
}

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

func main() {
var req = rpcData{"fn", []interface{}{1, "aaa"}}
rpcCall(req)
} func rpcCall(data rpcData) {
conn, err := net.Dial("tcp4", "127.0.0.1:3001")
if err != nil {
panic(err)
}
req, err := json.Marshal(data)
if err != nil {
panic(err)
}
buf := make([]byte, 4+len(req))
binary.BigEndian.PutUint32(buf[:4], uint32(len(req)))
copy(buf[4:], req)
_, err = conn.Write(buf)
if err != nil {
panic(err)
}
}

测试时,首先运行 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. windows server2012在已有.net4.5框架的基础上安装.net3.5的方法

    我们在一台服务器运行各种程序的时候难免会用到一些好用的但是很老的软件.老软件也就难免需要以前的那种环境来运行,但是老的环境与新的环境往往不兼容.下面我就来讲一讲系统在已有.net4.5的情况下怎么安装 ...

  2. MySql多表查询优化

    一.多表查询连接的选择 相信内连接,左连接什么的大家都比较熟悉了,当然还有左外连接什么的,基本用不上,我就补贴出来了,这个图只是让大家熟悉一下各种连接查询.然后要告诉大家的是,需要根据查询的信息,想好 ...

  3. android中shape的使用介绍-2环形

    匿名内部类不能修改外部类的临时变量,但属性变量可以访问 参考:http://blog.csdn.net/north1989/article/details/52939888

  4. 构建操作mysql的类

    <?phpclass PdoMySQL{ public static $config=array();//设置连接参数,配置信息 public static $link=null;//保存连接标 ...

  5. Remap 后的 USART1 不能发送数据

    最近在使用 STM32 的 USART1 时,遇到一点问题,记录一下. 如果 USART1 不是使用 PA9 和 PA10 作接收和发送引脚,而是 PB6 和 PB7,那么有一点就一定得注意了:此时 ...

  6. ArchLinux的安装

    ArichLinux安装教程 Arch Linux 于 2002 年发布,由 Aaron Grifin 领头,是当下最热门的 Linux 发行版之一.从设计上说,Arch Linux 试图给用户提供简 ...

  7. 使用java实现单链表(转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html)

    使用java实现单链表----(java中的引用就是指针)转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html ? 1 2 3 4 5 6 7 ...

  8. opencv3.1.0 计算机中丢失 opencv_world310d.dll _vs2017解决方法

    ---------------------------opencv1.exe - 系统错误---------------------------无法启动此程序,因为计算机中丢失 opencv_worl ...

  9. Eplan如何调用经常使用的自绘部件?

    Eplan如何调用经常使用的自绘部件?采用宏的简单应用,即可. 参考文档:https://blog.csdn.net/txwtech/article/details/90510106

  10. Mybatis框架-CRUD

    1  2  3  传统dao开发实现CRUD 3.1    传统dao开发实现crud 使用 Mybatis 开发 Dao,通常有两个方法,即原始 Dao开发方式和 Mapper 接口代理开发方式.而 ...