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) error
GetDBIndex() int
SelectDB(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()是系统的错误方法文章来源:https://www.toymoban.com/news/detail-614704.html
type ErrorReply interface {
Error() string
ToBytes() []byte
}
error.go 固定异常回复文章来源地址https://www.toymoban.com/news/detail-614704.html
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协议解析器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!