Go重写Redis中间件 - Go实现Redis协议解析器
Go实现Redis协议解析器
Redis网络协议详解
在解决完通信后,下一步就是搞清楚 Redis 的协议-RESP协议,其实就是一套类似JSON、Protocol Buffers的序列化协议,也就是我们的客户端和服务端通信的协议
RESP定义了5种格式
- 简单字符串(Simple String) : 服务器用来返回简单的结果,以"+"开头,"\r\n"结尾的字符串形式,比如 "+OK\r\n"
- 错误信息(Error) : 服务器用来返回简单的错误信息,以"-"开头,"\r\n"结尾的字符串形式,比如 "-ERR message\r\n"
- 整数(Integer) : 服务器端和客户端用来互相通信的格式,以":"开头,"\r\n"结尾的字符串形式,比如":123456\r\n"
- 字符串(Bulk String) : 以"$"开头,后跟实际发送字节数,以"\r\n"结尾,比如"$3\r\nSET\r\n",空字符串"$0\r\n\r\n","$9\r\nLBJ\r\nAD"
- 数组(Array) : 以*开头,后跟成员个数,比如"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"
实现RESP协议
创建两个resp协议接口,首先是conn.go,这个接口是在Redis协议层代表客户端的连接,里面定义3个方法,分别是:Write()用来给客户端回复消息;GetDBIndex()用来查询客户端用的哪个DB;SelectDB()用来切换Redis间的库
type Connection interface {Write([]byte) errorGetDBIndex() intSelectDB(int)
}
然后是reply.go,这个接口是代表各种客户端对服务端数据的回复,他是用来把回复的内容转成字节,因为TCP协议来回写就是写字节
type Reply interface {ToBytes() []byte
}
接下来就是RESP协议的实现,在resp文件夹里实现各种服务端对客户端的回复
consts.go 固定正常回复
type PongReply struct{}
var pongBytes = []byte("+PONG\r\n")
func (r *PongReply) ToBytes() []byte {return pongBytes
}
func MakePangReply() *PongReply {return &PongReply{}
}type OkReply struct{}
var okBytes = []byte("+OK\r\n")
func (r *OkReply) ToBytes() []byte {return okBytes
}
//回复常量,节约内存
var theOkReply = new(OkReply)
func MakeOkReply() *OkReply {return theOkReply
}//空字符串 null
var nullBulkBytes = []byte("$-1\r\n")
type NullBulkReply struct{}
func (r *NullBulkReply) ToBytes() []byte {return nullBulkBytes
}
func MakeNullBulkReply() *NullBulkReply {return &NullBulkReply{}
}//空数组
var emptyMultiBulkBytes = []byte("*0\r\n")
type EmptyMultiBulkReply struct{}
func (r *EmptyMultiBulkReply) ToBytes() []byte {return emptyMultiBulkBytes
}
func MakeEmptyMultiBulkReply() *EmptyMultiBulkReply {return &EmptyMultiBulkReply{}
}type NoReply struct{}
var noBytes = []byte("")
func (r *NoReply) ToBytes() []byte {return noBytes
}
然后是创建一个reply.go接口承载错误回复,其中Error()是系统的错误方法
type ErrorReply interface {Error() stringToBytes() []byte
}
error.go 固定异常回复
type UnknownErrReply struct{}
var unknownErrBytes = []byte("-Err unknown\r\n")
func (r *UnknownErrReply) ToBytes() []byte {return unknownErrBytes
}
func (r *UnknownErrReply) Error() string {return "Err unknown"
}// ArgNumErrReply represents wrong number of arguments for command
type ArgNumErrReply struct {Cmd string
}
func (r *ArgNumErrReply) ToBytes() []byte {return []byte("-ERR wrong number of arguments for '" + r.Cmd + "' command\r\n")
}
func (r *ArgNumErrReply) Error() string {return "ERR wrong number of arguments for '" + r.Cmd + "' command"
}
func MakeArgNumErrReply(cmd string) *ArgNumErrReply {return &ArgNumErrReply{Cmd: cmd,}
}// SyntaxErrReply represents meeting unexpected arguments
type SyntaxErrReply struct{}
var syntaxErrBytes = []byte("-Err syntax error\r\n")
var theSyntaxErrReply = &SyntaxErrReply{}
func MakeSyntaxErrReply() *SyntaxErrReply {return theSyntaxErrReply
}
func (r *SyntaxErrReply) ToBytes() []byte {return syntaxErrBytes
}
func (r *SyntaxErrReply) Error() string {return "Err syntax error"
}// WrongTypeErrReply represents operation against a key holding the wrong kind of value
type WrongTypeErrReply struct{}
var wrongTypeErrBytes = []byte("-WRONGTYPE Operation against a key holding the wrong kind of value\r\n")
func (r *WrongTypeErrReply) ToBytes() []byte {return wrongTypeErrBytes
}
func (r *WrongTypeErrReply) Error() string {return "WRONGTYPE Operation against a key holding the wrong kind of value"
}// ProtocolErrReply represents meeting unexpected byte during parse requests
type ProtocolErrReply struct {Msg string
}
func (r *ProtocolErrReply) ToBytes() []byte {相关文章:
Go重写Redis中间件 - Go实现Redis协议解析器
Go实现Redis协议解析器 Redis网络协议详解 在解决完通信后,下一步就是搞清楚 Redis 的协议-RESP协议,其实就是一套类似JSON、Protocol Buffers的序列化协议,也就是我们的客户端和服务端通信的协议 RESP定义了5种格式 简单字符串(Simple String) : 服务器用来返回简单的结…...
海外抖音Tiktok强势来袭,有些人半年赚别人十倍工资
TikTok作为一款流行的短视频社交应用程序,确实在全球范围内取得了很大的成功。许多人通过在TikTok上分享有趣、创意或有吸引力的视频内容,获得了广泛的关注和认可。一些用户甚至能够通过TikTok赚取高额的收入,远远超过传统职业所能获得的工资…...
devDept Eyeshot 2024 预告-Update-Crack
即将发布的版本 开发商在一个动态的环境中运作,事情可能会发生变化。本页提供的信息旨在概述 devDept 软件产品的总体方向。它仅供参考,不应作为做出任何决定性的依据。devDept Eyeshot 2024软件产品描述的任何特性或功能的开发、发布和时间安排仍由 dev…...
教雅川学缠论05-线段
线段需要满足下面4个条件: 1.是由3条笔,或者3条以上组成,同笔一样,线段也是有方向的 2.如果线段起始于向上笔,则终止与向上笔(一定不会终止与向下笔) 3.如果线段起始于向下笔,则终止…...
SpringBoot 配置⽂件
1.配置文件作用 整个项⽬中所有重要的数据都是在配置⽂件中配置的,⽐如: 数据库的连接信息(包含⽤户名和密码的设置);项⽬的启动端⼝;第三⽅系统的调⽤秘钥等信息;⽤于发现和定位问题的普通⽇…...
基于Python的电影票房爬取与可视化系统的设计与实现
博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…...
Packet Tracer – 配置系统日志和 NTP
Packet Tracer – 配置系统日志和 NTP 目标 第 1 部分:配置系统日志服务 第 2 部分:生成日志记录事件 第 3 部分:手动设置交换机时钟 第 4 部分:配置 NTP 服务 第 5 部分:验证带时间戳的日志 拓扑图 场景 在本…...
TypeScript 联合类型,类型推断,类型断言
联合类型 取值可以为多种类型中的一个 function func(str: number | string):void{}类型断言 当变量需要调用某属性的时候,有不确定当前的类型是什么,可以使用类型断言; 类型断言的两种方式: 1,<类型> 变量名…...
到底叫 集合还是数组还是list还是列表?
1 总体上可以将数据结构分为数组和集合两种,而列表是一个泛指 数组:在Java中,数组是一种基本数据类型,可以用来存储同一类型的多个元素,数组的长度是固定的。例如:int[] arr new int[10];List:…...
LBERT论文详解
论文地址:https://arxiv.org/abs/2105.07148 代码地址:https://github.com/liuwei1206/LEBERT 模型创新 LEBRT采用句子中的词语对(论文中称为Char-Word Pair)的特征作为输入作者设计Lexicon adapter,在BERT的中间某一…...
C++终止cin输入while循环时多读取^Z或^D的问题
原代码: istream& operator>>(istream& is, map<string, int>&mm) {string ss"";int ii0;is >> ss>>ii;mm[ss]ii;return is; }int main() {map<string,int>msi;while(cin>>msi);return 0; } 问题&…...
c#[WebMethod]方法接收前端传入的JsonArray的方法
一、第一种方法:可以这样接收前端传入的jsonArray字符串到一个类的数组中,然后遍历该数组取值 这种方法需要创建PointConfig类 class PointConfig{public string ptcrossing { get; set; }public string ptcrossingId { get; set; }public string camId …...
WebService 报错 集锦
报错1:url错误 我的是调用的url的端口错误。调用esb的url的端口错了,导致报错。有的人是uri错了。例如: www.globalcoding.com:9001/SAP_saveProduct/1.0.0 写成了 www.globalcoding.com:9001/SAP_savePoduct/1.0.0 报错如下:…...
C++--菱形继承
1.什么是菱形继承 单继承:一个子类只有一个直接父类时称这个继承关系为单继承 多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承 菱形继承的问题:菱形继承有数据冗余和二义性的问题,数据冗余是由于创建多个相同类型的…...
Vue 3:玩一下web前端技术(二)
前言 本章内容为VUE目录结构解析与相关工程技术讨论。 上一篇文章地址: Vue 3:玩一下web前端技术(一)_Lion King的博客-CSDN博客 下一篇文章地址: Vue 3:玩一下web前端技术(三)…...
自然语言处理14-基于文本向量和欧氏距离相似度的文本匹配,用于找到与查询语句最相似的文本
大家好,我是微学AI,今天给大家介绍一下自然语言处理14-基于文本向量和欧氏距离相似度的文本匹配,用于找到与查询语句最相似的文本。NLP中的文本匹配是指通过计算文本之间的相似度来找到与查询语句最相似的文本。其中一种常用的方法是基于文本…...
iOS开发-聊天emoji表情与自定义动图表情左右滑动控件
iOS开发-聊天emoji表情与自定义动图表情左右滑动控件 之前开发中遇到需要实现聊天emoji表情与自定义动图表情左右滑动控件。使用UICollectionView实现。 一、效果图 二、实现代码 UICollectionView是一种类似于UITableView但又比UITableView功能更强大、更灵活的视图&#x…...
Mybatis plus 存储 List、Map
目录 一、前提概要1.1 支持环境1.2 需求场景 二、需求实现2.1 非自定义数据类型,List、Map2.2 自定义类型数据类型 一、前提概要 1.1 支持环境 数据库支持:MySql版本要求 5.7 1.2 需求场景 使用MySQL数据库存储时,由于业务要求实体类中特…...
Electron 系统通知 Notification 实践指南
系统通知是桌面应用的常见功能,用于给用户发送提醒(刷下存在感 🙂),还能帮定点击事件以便后续的操作。 Electron 自带通知模块,下方代码是一个简单的示例 const { Notification } require(electron)cons…...
配置代理——解决跨域问题(详解)
之前写项目的时候总会遇到配置代理的问题,可是配置了之后有时有用,有时就没有用,自己之前学的也是懵懵懂懂,于是专门花了一个小时去了解了如何配置代理跨域,然后在此记录一下,方便自己以后查阅。 一、 常用…...
Qwen3-TTS WebUI使用技巧:长文本自动分段+情感一致性保持方法
Qwen3-TTS WebUI使用技巧:长文本自动分段情感一致性保持方法 Qwen3-TTS-12Hz-1.7B-CustomVoice 是一款强大的语音合成模型,支持10种主要语言和多种方言语音风格,具备出色的上下文理解能力和情感表达能力。但在处理长文本时,如何保…...
AI风口来袭!转型LLM应用开发工程师,非常详细收藏我这一篇就够了
一、引言:AI时代下的新职业机遇 近年来,随着人工智能技术的快速发展,尤其是大语言模型(Large Language Models, LLM)的突破,软件行业正在经历深刻变革。以GPT系列模型为代表的技术,使自然语言理…...
高效实时换脸架构优化:Deep-Live-Cam技术实现与部署方案
高效实时换脸架构优化:Deep-Live-Cam技术实现与部署方案 【免费下载链接】Deep-Live-Cam real time face swap and one-click video deepfake with only a single image 项目地址: https://gitcode.com/GitHub_Trending/de/Deep-Live-Cam Deep-Live-Cam是一款…...
什么是哈希算法?(大白话+原理+应用,一次讲透)
文章目录一、一句话定义二、用生活例子秒懂对应到代码里:三、哈希算法的核心特性(面试必背)四、为什么 HashSet.contains() 是 O(1)?(结合哈希原理)五、哈希算法的常见应用(你日常都在用&#x…...
告别兼容性烦恼,让老旧应用在现代浏览器中“无缝”运行
在数字化转型的浪潮中,企业的技术架构往往承载着历史的痕迹。当我们享受着现代浏览器带来的极速体验与丰富扩展时,一个不容忽视的挑战正悄然影响着员工的工作效率与IT运维的平静——那就是“传统浏览器支持”问题。这并非一个遥不可及的技术概念…...
YimMenu:GTA5游戏体验增强与安全防护指南
YimMenu:GTA5游戏体验增强与安全防护指南 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu 项目…...
YimMenu:GTA5游戏体验增强工具全攻略
YimMenu:GTA5游戏体验增强工具全攻略 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu 核心痛点…...
Python 如何反向 `enumerate` 遍历枚举
在 Python 中,enumerate() 是一个常用的内置函数,用于在遍历可迭代对象(如列表、元组、字符串等)时同时获取索引和值。但默认情况下,enumerate() 是从前往后遍历的。那么,**如何反向 enumerate 遍历&#x…...
微信聊天记录的数字档案馆:WeChatMsg实现数据永久保存与深度分析
微信聊天记录的数字档案馆:WeChatMsg实现数据永久保存与深度分析 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trendin…...
K8s定时任务实战:如何用CronJob每分钟输出Hello World(附表达式详解)
K8s定时任务实战:从Hello World到生产级CronJob配置 在云原生技术栈中,定时任务作为自动化运维的核心组件,其重要性不言而喻。Kubernetes提供的CronJob资源,让开发者能够以声明式的方式管理周期性任务,而无需依赖传统…...
