1 Star 1 Fork 2

pdudo/golearn

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
main.go 4.36 KB
一键复制 编辑 原始数据 按行查看 历史
pdudo 提交于 2022-09-02 10:21 +08:00 . update Redis/MasterSlave/main.go.
package main
import (
"bufio"
"errors"
"fmt"
"net"
"strconv"
"strings"
)
var toSlaveCommand map[string]bool
var (
redisMasterConn string = "127.0.0.1:6379"
redisSlaveConn string = "127.0.0.1:6380"
)
func main() {
l,err := net.Listen("tcp","0.0.0.0:8888")
if err != nil {
panic(err)
}
fmt.Println("服务器已经启动好了,监听地址: 0.0.0.0:8888")
// 维护从库执行的命令
toSlaveCommand = make(map[string]bool,0)
// key
toSlaveCommand["GET"] = true
// list
toSlaveCommand["LLEN"] = true
toSlaveCommand["LRANGE"] = true
// hash
toSlaveCommand["HEXISTS"] = true
toSlaveCommand["HGET"] = true
toSlaveCommand["HLEN"] = true
toSlaveCommand["HLEN"] = true
// set
for {
conn ,err := l.Accept()
if err != nil {
fmt.Println("accept error " , err)
continue
}
fmt.Println(conn.RemoteAddr()," 连接到Redis中转服务器")
// 为连接上来的每个conn分配主从redis conn
masterConn , err := net.Dial("tcp",redisMasterConn);if err != nil {
fmt.Println("dial redis master conn error: " , err)
continue
}
slaveConn, err := net.Dial("tcp",redisSlaveConn);if err != nil {
fmt.Println("dial redis slave conn error: " , err)
continue
}
go worker(conn,masterConn,slaveConn)
}
}
// worker
func worker(conn net.Conn,masterRedisConn net.Conn,slaveRedisConn net.Conn) {
defer func() {
fmt.Println(conn.RemoteAddr()," 断开连接")
conn.Close()
masterRedisConn.Close()
slaveRedisConn.Close()
}()
reader := bufio.NewReader(conn)
for {
var ss []interface{}
if toArgs(reader,&ss) != nil {
conn.Write([]byte(string("-client send msg error")))
return
}
com := genArrayArgs(ss)
switch strings.ToTitle(ss[0].(string)) {
case "COMMAND":
conn.Write([]byte(string("+OK\r\n")))
case "AUTH":
fmt.Println(conn.RemoteAddr(),"获取命令: " ,ss,"转发到主库")
toAgent(com,conn,masterRedisConn,true)
fmt.Println(conn.RemoteAddr(),"获取命令: " ,ss,"转发到从库")
toAgent(com,conn,slaveRedisConn,false)
default:
_ ,ok := toSlaveCommand[strings.ToTitle(ss[0].(string))]; if ok {
fmt.Println(conn.RemoteAddr(),"获取命令: " ,ss,"转发到从库")
toAgent(com,conn,slaveRedisConn,true)
} else {
fmt.Println(conn.RemoteAddr(),"获取命令: " ,ss,"转发到主库")
toAgent(com,conn,masterRedisConn,true)
}
}
}
}
// 转发信息到真实的服务器
func toAgent(com []byte,conn net.Conn,redisConn net.Conn,flag bool) {
redisConn.Write(com)
buf := make([]byte,10240000)
n , err := redisConn.Read(buf)
if err != nil {
fmt.Println(err)
}
if flag {
conn.Write(buf[:n])
}
}
// 将[]interface 类型转换为RESP数据
func genArrayArgs(ss []interface{}) (respMsg []byte) {
bodyLen := len(ss)
respMsg = append(respMsg, []byte(string("*"))...)
respMsg = append(respMsg, []byte(strconv.Itoa((bodyLen)) + "\r\n")...)
for i:=0;i<len(ss);i++ {
switch ss[i].(type) {
case int:
respMsg = append(respMsg, []byte(string(":"))...)
x := ss[i].(int)
respMsg = append(respMsg, []byte(strconv.Itoa((x)) + "\r\n")...)
case string:
respMsg = append(respMsg, []byte(string("$"))...)
str1 := ss[i].(string)
respMsg = append(respMsg, []byte(string(strconv.Itoa((len(str1))) + "\r\n"))...)
respMsg = append(respMsg, []byte(string(str1+"\r\n"))...)
}
}
return
}
// 将RESP转换为[]interface 类型
func toArgs(reader *bufio.Reader,ss *[]interface{}) (error) {
line , _ , _ := reader.ReadLine()
if len(line) < 2 {
return errors.New("获取报文有误")
}
switch line[0] {
case '*':
n , err := byteToInt(line[1:]);if err != nil {
return errors.New("转为数字错误")
}
// 递归
for i:=0;i<n;i++ {
toArgs(reader,ss)
}
case '$':
n , err := byteToInt(line[1:]);if err != nil {
return errors.New("转为数字错误")
}
buf := make([]byte,n)
_,err = reader.Read(buf) ; if err != nil {
return errors.New("获取命令失败")
}
*ss = append(*ss, string(buf))
crlf := make([]byte,2)
reader.Read(crlf)
if string(crlf) != "\r\n" {
return errors.New("获取命令失败")
}
}
return nil
}
// []byte 转为 int
// 例如 []byte(string("11")) 转为 int类型的 11
func byteToInt(number []byte) (int , error) {
var sum int
x := 1
for i:=len(number)-1;i>=0;i-- {
if number[i] < '0' || number[i] > '9' {
return 0 , errors.New("toNumberError")
}
sum += int(number[i] - '0') * x
x = x * 10
}
return sum,nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/pdudo/golearn.git
git@gitee.com:pdudo/golearn.git
pdudo
golearn
golearn
master

搜索帮助