目的
通過搭建一個高可用的redis客戶端來學習redis,go語言,以及go一些設計模式
參考資料
go-redis源碼
《redis設計與實現》
學習思路
循環漸進,從最簡單的一步步迭代
一個最簡單的能跑通的redis客戶端例子
package main
import (
"fmt"
"net"
"strings"
)
type options struct {
Network string
Addr string
}
func (p *options) init() {
if p.Addr == "" {
p.Addr = "127.0.0.1:6379"
}
if p.Network == "" {
p.Network = "tcp"
}
}
//redis struct
type redisClient struct {
opt options
conn net.Conn
sendCmd string
reply string
}
func (c *redisClient) connect() {
conn, err := net.Dial(c.opt.Network, c.opt.Addr)
if err != nil {
fmt.Println("connect err ", err)
}
c.conn = conn
}
func (c *redisClient) sendCommand(cmd string) string {
c.formatCommand(cmd)
c.write()
return c.getReply()
}
func (c *redisClient) formatCommand(cmd string) {
var protocl_cmd string
cmd_argv := strings.Fields(cmd)
protocl_cmd = fmt.Sprintf("*%d\r\n", len(cmd_argv))
for _, arg := range cmd_argv {
protocl_cmd += fmt.Sprintf("$%d\r\n", len(arg))
protocl_cmd += arg
protocl_cmd += "\r\n"
}
//redis服務器接受的命令協議
fmt.Printf("%q\n", protocl_cmd)
c.sendCmd = protocl_cmd
}
func (c *redisClient) write() {
c.conn.Write([]byte(c.sendCmd))
c.sendCmd = ""
}
func (c redisClient) getReply() string {
byte_len := 1024 * 16
reply := make([]byte, byte_len)
//暫時簡化一次輸出完
c.conn.Read(reply)
return string(reply)
}
func NewClient(opt options) *redisClient {
c := redisClient{
opt: opt,
}
c.opt.init()
c.connect()
return &c
}
func main() {
c := NewClient(options{
Addr: "127.0.0.1:6379",
})
rep := c.sendCommand("set hello world")
fmt.Println(rep)
}
上面這個例子,暫時沒考慮讀寫循環,錯誤處理,主要實現了發送redis服務器命令協議內容,以及客戶端連接