从零实现GeeRPC框架:第一天构建服务端与消息编码

从零实现GeeRPC框架:第一天构建服务端与消息编码

7days-golang 7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列 7days-golang 项目地址: https://gitcode.com/gh_mirrors/7d/7days-golang

前言

在分布式系统中,远程过程调用(RPC)是一种常见的通信方式。本文将带领大家从零开始实现一个名为GeeRPC的RPC框架,第一天我们将聚焦于服务端基础架构和消息编码机制的实现。

RPC基础概念

RPC(Remote Procedure Call)允许程序像调用本地方法一样调用远程服务的方法。一个典型的RPC调用包含三个关键部分:

  • 服务名和方法名
  • 参数
  • 返回值

在GeeRPC中,我们将这些信息抽象为Header和Body两部分,Header包含元数据,Body包含实际数据。

消息编码设计

Header结构设计

首先我们定义Header结构体:

type Header struct {
    ServiceMethod string // 格式为"Service.Method"
    Seq           uint64 // 客户端选择的序列号
    Error         string // 错误信息
}
  • ServiceMethod:标识要调用的服务和方法
  • Seq:请求的唯一标识符
  • Error:服务端返回的错误信息

编解码接口

为了实现灵活的编码方式,我们定义了Codec接口:

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

这个接口支持:

  1. 读取Header
  2. 读取Body
  3. 写入Header和Body
  4. 关闭连接

编解码工厂模式

我们采用工厂模式支持多种编码方式:

type NewCodecFunc func(io.ReadWriteCloser) Codec

type Type string

const (
    GobType  Type = "application/gob"
    JsonType Type = "application/json"
)

var NewCodecFuncMap map[Type]NewCodecFunc

目前实现了Gob编码,未来可以轻松扩展JSON等其他编码方式。

Gob编码实现

Gob是Go语言自带的二进制序列化格式,我们基于它实现GobCodec:

type GobCodec struct {
    conn io.ReadWriteCloser
    buf  *bufio.Writer
    dec  *gob.Decoder
    enc  *gob.Encoder
}

实现要点:

  • 使用bufio.Writer缓冲提高性能
  • 分离Decoder和Encoder分别处理读写
  • 实现了完整的Codec接口方法

服务端实现

协议设计

客户端和服务端通信需要协商编码方式,我们定义Option结构:

type Option struct {
    MagicNumber int        // 标识GeeRPC请求
    CodecType   codec.Type // 编码类型
}

通信报文格式如下:

| Option | Header1 | Body1 | Header2 | Body2 | ...

服务端核心结构

服务端核心结构非常简单:

type Server struct{}

主要方法包括:

  • Accept:接受连接并处理
  • ServeConn:处理单个连接
  • serveCodec:使用指定编解码器处理请求

请求处理流程

  1. 首先解析Option确定编码方式
  2. 循环读取请求(readRequest)
  3. 并发处理请求(handleRequest)
  4. 顺序回复请求(sendResponse)

关键点:

  • 使用协程并发处理请求提高性能
  • 使用互斥锁保证回复顺序
  • 使用WaitGroup等待所有请求处理完成

请求数据结构

type request struct {
    h            *codec.Header
    argv, replyv reflect.Value
}

目前argv和replyv都简单处理为字符串,后续会改进。

示例演示

我们实现了一个简单的客户端和服务端交互示例:

服务端:

func startServer(addr chan string) {
    l, _ := net.Listen("tcp", ":0")
    addr <- l.Addr().String()
    geerpc.Accept(l)
}

客户端:

conn, _ := net.Dial("tcp", <-addr)
cc := codec.NewGobCodec(conn)
// 发送请求并接收响应

总结

第一天我们实现了:

  1. 基于Gob的消息编解码器
  2. 服务端基础架构
  3. 简单的协议协商机制
  4. 请求处理流程

虽然目前功能还比较简单,但已经建立了RPC框架的核心骨架。在后续开发中,我们将逐步完善客户端实现、服务注册、超时处理等高级特性。

完整代码约200行,涵盖了RPC框架最基础的功能。通过这个实现,我们可以深入理解RPC框架的工作原理,为后续扩展打下坚实基础。

7days-golang 7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列 7days-golang 项目地址: https://gitcode.com/gh_mirrors/7d/7days-golang

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平均冠Zachary

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值