2022年的第一个rpc,比以往来的更早一些...

留杭过年...写点东西

初始化项目gorpc

借助go module我们可以轻易创建一个新的项目

mkdir gorpc
go mod init github.com/taadis/gorpc // output:
go: creating new go.mod: module github.com/taadis/gorpc

消息约定

rpc 的客户端和服务端之间通信需要传输数据消息,典型的消息结构一般有2部分组成

  • header 消息头 - 用来承载约定内容,一般是相对固定的。
  • body 消息体 - 用来承载用户数据,通常是不定长,也就是动态的

这里我们先定义更泛的消息体,因为消息体是动态的,所以我们可以直接用go中的 interface{} 来定义,就不用特别声明一个结构体了。

然后我们来定义一个header结构体

// codec.go

type Header struct {
Sequence uint64 // sequence number chosen by client
ServiceMethod string // format "Service.Method"
Error error
}

Sequence 序列号是客户端带过来的,每个请求总要有点不一样的地方,方便服务端根据序列号来区分不同的调用,可以理解是唯一ID。

ServiceMethod 是要远程调用的服务下的方法名词,这里对照为go语言中结构体的方法名,比如用户创建方法"User.Create"。

Error 是错误信息,用来放置一端发生的错误,以便另一种接收到消息时能根据错误进行处理,而不是直接丢失响应。

消息的编码解码

rpc 的客户端和服务端之间通信的消息有其特有的格式,因此都需要涉及编码和解码这一关键步骤,也就是我们熟称的序列化和反序列化。

以便抽象理解,我们定义一个统一的Codec接口

// codec.go

type Codec interface {
ReadHeader(*Header) error
ReadBody(interface{}) error
Write(*Header, interface{}) error
}

ReadHeader 读取信息头,如果有错误返回错误。

ReadBody 读取消息体,数据是动态的,所以使用interface{}作为参数,如果有错误返回错误。

Write 消息接收处理完成后,我们需要把结果告知给客户端,需要一个写入的操作。

这里我们借助标准库内置的encoding/gob来提高工作效率。

当然你也可以用encoding/json,encoding/xml或者其他编解码包,这里选择encoding/gob,仅仅是因为这是go所特有的。JUST GO。

接下来我们基于encoding/gob实现一个gobCodec

rpc 请求是一种网络请求,本质还是I/O,所以我们可以用io.ReadWriteCloser来定义网络链接conn.

通过gob.Decoder解码请求中的数据流至对应的结构体参数,

完成服务端调用之后,把返回结果再用gob.Encoder编码至数据流中,

最后通过bufio.Writer写入数据完成响应。

// codec.go

type gobCodec struct {
conn io.ReadWriteCloser
decoder *gob.Decoder
encoder *gob.Encoder
writeBuf *bufio.Writer
}

封装一个newGobCodec函数,方便后续调用。

func newGobCodec(conn io.ReadWriteCloser) Codec {
writeBuf := bufio.NewWriter(conn)
return &gobCodec{
conn: conn,
decoder: gob.NewDecoder(conn),
encoder: gob.NewEncoder(writeBuf),
writeBuf: writeBuf,
}
}

实现 Codec 接口中的 ReadHeader 方法

func (c *gobCodec) ReadHeader(header *Header) error {
return c.decoder.Decode(header)
}

实现 Codec 接口中的 ReadBody 方法

func (c *gobCodec) ReadBody(body interface{}) error {
return c.decoder.Decode(body)
}

实现 Codec 接口中的 Write 方法

func (c *gobCodec) Write(header *Header, body interface{}) error {
defer func() {
if c.writeBuf.Flush() != nil {
c.conn.Close()
}
}() if err := c.encoder.Encode(header); err != nil {
return err
} if err := c.encoder.Encode(body); err != nil {
return err
} return nil
}

至此,rpc 中比较底层的数据编码和解码我们已经抽象出来了Codec接口,并借助encoding/gob实现了gobCodec.

举个栗子之gorpc - 消息的编码和解码的更多相关文章

  1. celery消息的编码和序列化(转)

    add by zhj: 原文讲的是序列化时的安全问题,不过,我关心的是怎样可以看到消息队列中的数据.下面是在broker中看到的消息,body是先用 body_encoding编码,然后用conten ...

  2. URL编码及解码

    为什么要对URL进行编码? 一般来说,网页URL只能使用英文.数字.还有一些特定的字符.根据网络标准RFC 1738做了硬性规定: 只有字母和数字[0-9a-zA-Z].一些特殊符号"$-_ ...

  3. BASE64编码和解码(VC源代码) 并 内存加载 CImage 图像

      BASE64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本.完整的BASE64定义可见 RFC1421和 RFC2045.编码后的数据比原始数据略长,为原来的4/3.在电子 ...

  4. Python2/3的中、英文字符编码与解码输出: UnicodeDecodeError: 'ascii' codec can't decode/encode

    摘要:Python中文虐我千百遍,我待Python如初恋.本文主要介绍在Python2/3交互模式下,通过对中文.英文的处理输出,理解Python的字符编码与解码问题(以点破面). 前言:字符串的编码 ...

  5. Dubbo中编码和解码的解析

    (这里做的解析不是很详细,等到走完整个流程再来解析)Dubbo中编解码的工作由Codec2接口的实现来处理,回想一下第一次接触到Codec2相关的内容是在服务端暴露服务的时候,根据具体的协议去暴露服务 ...

  6. NIO框架之MINA源码解析(四):粘包与断包处理及编码与解码

    1.粘包与段包 粘包:指TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.造成的可能原因: 发送端需要等缓冲区满才发送出去,造成粘包 接收 ...

  7. 详解Base64编码和解码

    Base64是最常用的编码之一,比如开发中用于传递参数.现代浏览器中的<img />标签直接通过Base64字符串来渲染图片以及用于邮件中等等.Base64编码在RFC2045中定义,它被 ...

  8. JavaScript:详解 Base64 编码和解码

    Base64是最常用的编码之一,比如开发中用于传递参数.现代浏览器中的<img />标签直接通过Base64字符串来渲染图片以及用于邮件中等等.Base64编码在RFC2045中定义,它被 ...

  9. Web开发之编码与解码、签名、加密与解密

    在Web开发中,编码与解码.签名.加密与解密是非常常见的问题.本文不会介绍具体实例,而是介绍这些的原理.用途与区别.一.编码与解码        在Web开发中,需要通过URL的query参数来传递数 ...

  10. Java 8中的Base64编码和解码

    转自:https://juejin.im/post/5c99b2976fb9a070e76376cc Java 8会因为将lambdas,流,新的日期/时间模型和Nashorn JavaScript引 ...

随机推荐

  1. 内存吞金兽(Elasticsearch)的那些事儿 -- 写入&检索原理

    系列目录 内存吞金兽(Elasticsearch)的那些事儿 -- 认识一下 内存吞金兽(Elasticsearch)的那些事儿 -- 数据结构及巧妙算法 内存吞金兽(Elasticsearch)的那 ...

  2. 前端面试100-copy

    1.一些开放性题目 1.自我介绍:除了基本个人信息以外,面试官更想听的是你与众不同的地方和你的优势. 2.项目介绍 3.如何看待前端开发? 4.平时是如何学习前端开发的? 5.未来三到五年的规划是怎样 ...

  3. 聊一聊 操作系统蓝屏 c0000102 的故障分析

    一:背景 1. 讲故事 今年以来不知道为啥总有些朋友加我微信,让我帮忙分析下操作系统蓝屏问题,我也觉得挺好奇的,就问了其中一位朋友,说是B站来的,我就在拼命回忆,为啥会找我分析蓝屏?突然想到了去年好像 ...

  4. JS深度理解

    事件循环 程序运行需要有自己专属的内存空间,可以把这块内存简单理解为进程 每个应用至少有一个进程,进程间相互独立,要通信,也需要双方同意 线程 有进程后,就可以运行程序的代码 运行代码的 [人] 称为 ...

  5. 安全、高效!天翼云HPFS助企业一臂之力!

    近年来,随着各行业数智转型逐步深入以及人工智能大模型的蓬勃发展,气象分析.大模型训练.自动驾驶.石油勘探.EDA仿真.基因分析等高性能计算(HPC)场景和智算场景(AI)不仅对算力需求激增,也产生了图 ...

  6. Linux下普通用户免密切换root

    问题需求: Linux下普通用户doge免密切换root 问题解决: Linux下普通用户切换到root用户下,默认情况是需要输入密码很不方便,因此需要实现普通用户doge免密切换到root用户. 示 ...

  7. 普通人也能轻松掌握的20个DeepSeek高频提示词(2025版)

    一.基础原则 1️⃣ 说人话最重要 "不用专业术语,就像和朋友聊天一样描述需求". ️ 错误示范:"请用SWOT分析法输出新能源汽车行业报告". 正确示范:&q ...

  8. 搭建本地NCBI病毒库用于Blast

    搭建本地NCBI病毒库用于Blast 目的:为了通过Blast剔除我数据集中所有与Human任意片段相似度超过97%的序列 日期:2022/11/17 1. Nt库下载 创建conda环境 conda ...

  9. Python - [03] 基础语法

    题记部分 一.标识符 第一个字符必须是字母表中字母或下划线_ 标识符的其他部分由字母.数字和下划线组成 标识符对大小写敏感 二.Python保留字 三.注释 (1)单行注释:以#开头 #!/usr/b ...

  10. Hive - 多种表类型的CURD测试

    关于torc.textfile.orc.es.hyperdrive表的CURD测试 TORC(支持事务的orc表)测试 TORC(分区表)测试 TEXTFILE 表测试 ORC 表测试 ES(Elas ...