gedis:自己实现go语言的redis客户端 第三节(redis协议的处理)

redis的通信协议本文不做分析和解读,建议参考redis官方文档或其它博文,我们直接看实现:

redis相关命令及常量定义:

package protocol

const DOLLARBYTE = "$"
const ASTERISKBYTE = "*"
const PLUSBYTE = "+"
const MINUS_BYTE = "-"
const COLON_BYTE = ":"
const CRLF = "\r\n"
const BLANK = ""
const OK = "+OK\r\n"
const NONEXIST = "$-1"

const PING = "PING"
const SET = "SET"
const GET = "GET"
const QUIT = "QUIT"
const EXISTS = "EXISTS"
const DEL = "DEL"
const TYPE = "TYPE"
const FLUSHDB = "FLUSHDB"
const KEYS = "KEYS"
const RANDOMKEY = "RANDOMKEY"
const RENAME = "RENAME"
const RENAMENX = "RENAMENX"
const RENAMEX = "RENAMEX"
const DBSIZE = "DBSIZE"
const EXPIRE = "EXPIRE"
const EXPIREAT = "EXPIREAT"
const TTL = "TTL"
const SELECT = "SELECT"
const MOVE = "MOVE"
const FLUSHALL = "FLUSHALL"
const GETSET = "GETSET"
const MGET = "MGET"
const SETNX = "SETNX"
const SETEX = "SETEX"
const MSET = "MSET"
const MSETNX = "MSETNX"
const DECRBY = "DECRBY"
const DECR = "DECR"
const INCRBY = "INCRBY"
const INCR = "INCR"
const APPEND = "APPEND"
const SUBSTR = "SUBSTR"
const HSET = "HSET"
const HGET = "HGET"
const HSETNX = "HSETNX"
const HMSET = "HMSET"
const HMGET = "HMGET"
const HINCRBY = "HINCRBY"
const HEXISTS = "HEXISTS"
const HDEL = "HDEL"
const HLEN = "HLEN"
const HKEYS = "HKEYS"
const HVALS = "HVALS"
const HGETALL = "HGETALL"
const RPUSH = "RPUSH"
const LPUSH = "LPUSH"
const LLEN = "LLEN"
const LRANGE = "LRANGE"
const LTRIM = "LTRIM"
const LINDEX = "LINDEX"
const LSET = "LSET"
const LREM = "LREM"
const LPOP = "LPOP"
const RPOP = "RPOP"
const RPOPLPUSH = "RPOPLPUSH"
const SADD = "SADD"
const SMEMBERS = "SMEMBERS"
const SREM = "SREM"
const SPOP = "SPOP"
const SMOVE = "SMOVE"
const SCARD = "SCARD"
const SISMEMBER = "SISMEMBER"
const SINTER = "SINTER"
const SINTERSTORE = "SINTERSTORE"
const SUNION = "SUNION"
const SUNIONSTORE = "SUNIONSTORE"
const SDIFF = "SDIFF"
const SDIFFSTORE = "SDIFFSTORE"
const SRANDMEMBER = "SRANDMEMBER"
const ZADD = "ZADD"
const ZRANGE = "ZRANGE"
const ZREM = "ZREM"
const ZINCRBY = "ZINCRBY"
const ZRANK = "ZRANK"
const ZREVRANK = "ZREVRANK"
const ZREVRANGE = "ZREVRANGE"
const ZCARD = "ZCARD"
const ZSCORE = "ZSCORE"
const MULTI = "MULTI"
const DISCARD = "DISCARD"
const EXEC = "EXEC"
const WATCH = "WATCH"
const UNWATCH = "UNWATCH"
const SORT = "SORT"
const BLPOP = "BLPOP"
const BRPOP = "BRPOP"
const AUTH = "AUTH"
const SUBSCRIBE = "SUBSCRIBE"
const PUBLISH = "PUBLISH"
const UNSUBSCRIBE = "UNSUBSCRIBE"
const PSUBSCRIBE = "PSUBSCRIBE"
const PUNSUBSCRIBE = "PUNSUBSCRIBE"
const PUBSUB = "PUBSUB"
const ZCOUNT = "ZCOUNT"
const ZRANGEBYSCORE = "ZRANGEBYSCORE"
const ZREVRANGEBYSCORE = "ZREVRANGEBYSCORE"
const ZREMRANGEBYRANK = "ZREMRANGEBYRANK"
const ZREMRANGEBYSCORE = "ZREMRANGEBYSCORE"
const ZUNIONSTORE = "ZUNIONSTORE"
const ZINTERSTORE = "ZINTERSTORE"
const ZLEXCOUNT = "ZLEXCOUNT"
const ZRANGEBYLEX = "ZRANGEBYLEX"
const ZREVRANGEBYLEX = "ZREVRANGEBYLEX"
const ZREMRANGEBYLEX = "ZREMRANGEBYLEX"
const SAVE = "SAVE"
const BGSAVE = "BGSAVE"
const BGREWRITEAOF = "BGREWRITEAOF"
const LASTSAVE = "LASTSAVE"
const SHUTDOWN = "SHUTDOWN"
const INFO = "INFO"
const MONITOR = "MONITOR"
const SLAVEOF = "SLAVEOF"
const CONFIG = "CONFIG"
const STRLEN = "STRLEN"
const SYNC = "SYNC"
const LPUSHX = "LPUSHX"
const PERSIST = "PERSIST"
const RPUSHX = "RPUSHX"
const ECHO = "ECHO"
const LINSERT = "LINSERT"
const DEBUG = "DEBUG"
const BRPOPLPUSH = "BRPOPLPUSH"
const SETBIT = "SETBIT"
const GETBIT = "GETBIT"
const BITPOS = "BITPOS"
const SETRANGE = "SETRANGE"
const GETRANGE = "GETRANGE"
const EVAL = "EVAL"
const EVALSHA = "EVALSHA"
const SCRIPT = "SCRIPT"
const SLOWLOG = "SLOWLOG"
const OBJECT = "OBJECT"
const BITCOUNT = "BITCOUNT"
const BITOP = "BITOP"
const SENTINEL = "SENTINEL"
const DUMP = "DUMP"
const RESTORE = "RESTORE"
const PEXPIRE = "PEXPIRE"
const PEXPIREAT = "PEXPIREAT"
const PTTL = "PTTL"
const INCRBYFLOAT = "INCRBYFLOAT"
const PSETEX = "PSETEX"
const CLIENT = "CLIENT"
const TIME = "TIME"
const MIGRATE = "MIGRATE"
const HINCRBYFLOAT = "HINCRBYFLOAT"
const SCAN = "SCAN"
const HSCAN = "HSCAN"
const SSCAN = "SSCAN"
const ZSCAN = "ZSCAN"
const WAIT = "WAIT"
const CLUSTER = "CLUSTER"
const ASKING = "ASKING"
const PFADD = "PFADD"
const PFCOUNT = "PFCOUNT"
const PFMERGE = "PFMERGE"
const READONLY = "READONLY"
const GEOADD = "GEOADD"
const GEODIST = "GEODIST"
const GEOHASH = "GEOHASH"
const GEOPOS = "GEOPOS"
const GEORADIUS = "GEORADIUS"
const GEORADIUSBYMEMBER = "GEORADIUSBYMEMBER"
const BITFIELD = "BITFIELD"

请求参数进行编码:

package handler

import "protocol"

func HandleMultiBulkRequest(key string, elements []string) [][]byte{
	bytes := make([][]byte, len(elements)+1)
	bytes[0] = protocol.SafeEncode(key)
	for i := 0; i < len(elements); i++ {
		bytes[i+1] = protocol.SafeEncode(elements[i])
	}
	return bytes
}

func HandleBulkRequest(elements []string) [][]byte{
	bytes := make([][]byte, len(elements))
	for i := 0; i < len(elements); i++ {
		bytes[i] = protocol.SafeEncode(elements[i])
	}
	return bytes
}
package protocol

import "strconv"

func SafeEncode(arg string) []byte {
	return []byte(arg)
}

func SafeEncodeInt(arg int64) []byte {
	return SafeEncode(strconv.FormatInt(arg, 10))
}

消息发送模块:

package client

import (
	"net"
	"bytes"
	"protocol"
	"strconv"
	"fmt"
	"os"
)

func SendCommand(conn *net.TCPConn, cmd string, a ...[]byte) string {
	var buffer bytes.Buffer
	buffer.Write(protocol.SafeEncode(protocol.ASTERISKBYTE))
	buffer.Write(protocol.SafeEncode(strconv.Itoa(len(a) + 1)))
	buffer.Write(protocol.SafeEncode(protocol.CRLF))
	buffer.Write(protocol.SafeEncode(protocol.DOLLARBYTE))
	buffer.Write(protocol.SafeEncode(strconv.Itoa(len(cmd))))
	buffer.Write(protocol.SafeEncode(protocol.CRLF))
	buffer.Write(protocol.SafeEncode(cmd))
	buffer.Write(protocol.SafeEncode(protocol.CRLF))

	for _, arg := range a {
		buffer.Write(protocol.SafeEncode(protocol.DOLLARBYTE))
		buffer.Write(protocol.SafeEncode(strconv.Itoa(len(arg))))
		buffer.Write(protocol.SafeEncode(protocol.CRLF))
		buffer.Write(arg)
		buffer.Write(protocol.SafeEncode(protocol.CRLF))
	}
	return send(conn, buffer)
}

func send(conn *net.TCPConn, content bytes.Buffer) string {
	//send to server
	_, err := conn.Write(content.Bytes())

	if err != nil {
		fmt.Println(conn.RemoteAddr().String(), "server response")
		os.Exit(1)
	}

	buffer := make([]byte, 1024)
	//receive server info
	msg, err := conn.Read(buffer)
	if err != nil {
		fmt.Println(conn.RemoteAddr().String(), "server response:"+err.Error())
		os.Exit(1)
	}
	return string(buffer[:msg])
}

消息接收处理模块:

package handler

import (
	"strings"
	"protocol"
	"fmt"
	"github.com/emirpasic/gods/lists/arraylist"
)

/**
 * 处理redis响应的结果
 * 1、复杂的*...
 * 2、:数字
 * 3、简单的$...
 * 4、+OK
 * 5、-ERR(WRONGTYPE...)
 */
func HandleReply(result string) (interface{}, error) {
	if strings.HasPrefix(result, protocol.MINUS_BYTE) {
		return handleMinusReply(result)
	}

	if strings.HasPrefix(result, protocol.PLUSBYTE) {
		return handlePlusReply(result)
	}

	if strings.HasPrefix(result, protocol.COLON_BYTE) {
		return handleColonReply(result)
	}

	if strings.HasPrefix(result, protocol.DOLLARBYTE) {
		return handleDollarReply(result)
	}

	if strings.HasPrefix(result, protocol.ASTERISKBYTE) {
		return HandleAsteriskReply(result)
	}
	return nil, fmt.Errorf("reply handle err")
}

func HandleAsteriskReply(result string) (interface{}, error) {
	array := strings.Split(result, protocol.CRLF)
	results := arraylist.New()
	for i := 1; i < len(array)-1; i++ {
		if array[i] == protocol.NONEXIST {
			results.Add(nil)
			continue
		}
		results.Add(array[i+1])
		i++
		if i > len(array)-2 {
			break
		}
	}
	return results.Values(), nil
}

func handlePlusReply(result string) (interface{}, error) {
	if result != protocol.OK {
		return nil, fmt.Errorf(result)
	}
	return strings.ReplaceAll(strings.ReplaceAll(result, protocol.CRLF, protocol.BLANK), protocol.PLUSBYTE, protocol.BLANK), nil
}

func handleDollarReply(result string) (interface{}, error) {
	if strings.HasPrefix(result, protocol.NONEXIST) {
		return nil, nil
	}

	if !strings.HasPrefix(result, protocol.DOLLARBYTE) {
		return nil, fmt.Errorf(result)
	}
	array := strings.Split(result, protocol.CRLF)
	return array[1], nil
}

func handleColonReply(result string) (interface{}, error) {
	return strings.ReplaceAll(strings.ReplaceAll(result, protocol.CRLF, protocol.BLANK), protocol.COLON_BYTE, protocol.BLANK), nil
}

func handleMinusReply(result string) (interface{}, error) {
	return strings.ReplaceAll(strings.ReplaceAll(result, protocol.CRLF, protocol.BLANK), protocol.MINUS_BYTE, protocol.BLANK), nil
}

项目地址:

https://github.com/zhangxiaomin1993/gedis

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值