使用golang写一个redis-cli的方法示例

2020-01-28 13:38:17于海丽
func MultiUnMarsh(p []byte) ([][]byte, error) { if p[0] != '*' { return [][]byte{}, errors.New("format error") } n, err := ReadLine(p[1:]) if err != nil { return [][]byte{}, err } l, err := strconv.Atoi(string(n)) if err != nil { return [][]byte{}, err } // 多条批量回复也可以是空白的(empty) if l == 0 { return [][]byte{}, nil } // 无内容的多条批量回复(null multi bulk reply)也是存在的, // 客户端库应该返回一个 null 对象, 而不是一个空数组。 if l == -1 { return nil, nil } result := make([][]byte, l) t := len(n) + 3 for i := 0; i < l; i++ { ret, length, err := SingleUnMarshal(p[t:]) if err != nil { return [][]byte{}, errors.New("format error") } result[i] = ret t += length } return result, nil }

5. 命令行模式

一个可用的redis-cli自然是一个交互式的,用户输入指令然后输出返回值。在go中我们可以使用以下代码即可获得一个类似的交互式命令行


func main() {
 // ....
 for {
 fmt.Printf("%s:%d>", host, port)

 bio := bufio.NewReader(os.Stdin)
 input, _, err := bio.ReadLine()
 if err != nil {
  log.Fatal(err)
 }
 fmt.Printf("%sn", input)
 }
}

我们运行以上代码就可以实现


localhost:6379>set key liang
set key liang
localhost:6379>get key
get key
localhost:6379>

结合上我们的redis发送请求和解析请求即可完成整个redis-cli


func main() {
  // ....
 for {
 fmt.Printf("%s:%d>", host, port)

 // 获取输入命令和参数
 bio := bufio.NewReader(os.Stdin)
 input, err := bio.ReadString('n')
 if err != nil {
  log.Fatal(err)
 }
 fields := strings.Fields(input)

 // 编码发送请求
 req := MultiBulkMarshal(fields...)

 // 发送请求
 _, err = conn.Write([]byte(req))
 if err != nil {
  log.Fatal(err)
 }

 // 读取返回内容
 p := make([]byte, 1024)
 _, err = conn.Read(p)
 if err != nil {
  log.Fatal(err)
 }

 // 解析返回内容
 if p[0] == '*' {
  result, err := MultiUnMarsh(p)
 } else {
  result, _, err := SingleUnMarshal(p)
 }

  }
  // ....
}

6. 总结

到目前为止我们的cli程序已经全部完成,但其实还有很多不完美地方。但核心的redis协议解析已经完成,使用这个解析我们能完成任何的cli与服务器之间的交互

更详细的redis-cli实现可以参考我的github:A Simaple redis cli - Rclient

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持易采站长站。