上一篇文章我们用PHP来实现的redis服务端,这次我们用go来实现下,看看会有什么区别。
代码如下:
// redis_server project main.go
package main
import (
"strings"
"bufio"
"fmt"
"net"
"strconv"
)
var kv_data map[string]string
func main() {
kv_data = make(map[string]string)
//建立socket,监听端口
netListen, _ := net.Listen("tcp", ":1215")
defer netListen.Close()
fmt.Println("Waiting for clients")
for {
conn, err := netListen.Accept()
if err != nil {
continue
}
fmt.Println("Accept a client")
go handleConnection(conn)
}
}
//处理连接
func handleConnection(conn net.Conn) {
for {
str := parseRESP(conn)
switch value := str.(type) {
case string:
if len(value) == 0 {
goto end
}
conn.Write([]byte(value))
case []string:
if ( value[0] == "SET" ) {
key := string(value[1])
val := string(value[2])
kv_data[key] = val
conn.Write([]byte("+OK\r\n"))
}else if ( value[0] == "GET" ){
key := string(value[1])
val := string(kv_data[key])
val_len := strconv.Itoa(len(val))
str := "$"+val_len+"\r\n"+val+"\r\n"
conn.Write([]byte(str))
}else{
conn.Write([]byte("+OK\r\n"))
}
break
default:
}
}
end:
conn.Close()
}
func parseRESP(conn net.Conn) interface{} {
r := bufio.NewReader(conn)
line,err := r.ReadString('\n')
if err != nil {
return ""
}
cmd_type := string(line[0])
cmd_txt := strings.Trim(string(line[1:]),"\r\n")
switch cmd_type {
case "*":
count,_ := strconv.Atoi(cmd_txt)
var data []string
//"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n"
for i := 0; i < count; i++ {
line,_ := r.ReadString('\n')
cmd_txt := strings.Trim(string(line[1:]),"\r\n")
c,_ := strconv.Atoi(cmd_txt)
length := c + 2
str := ""
for length > 0 {
block,_ := r.Peek(length)
if length != len(block) {
}
r.Discard(length)
str += string(block)
length -= len(block)
}
data = append(data,strings.Trim(str,"\r\n"))
}
return data
default:
return cmd_txt
}
}
感兴趣的同学可以压测试对比下和PHP的区别
