基于tcp的内存缓存服务

Posted by FutureTechx on February 1, 2021

基于TCP的内存缓存服务

  • 和HTTP 包一样, TCP 包也有自己的Server 结构体,负责处理TCP 连接以及和客户端的交 ```go package main

type Server struct { cache.Cache }

func (s *Server) Listen(){ l,e :=net.Listen(“tcp”, “:123456”) if e != nil { panic(e) }

1
2
3
4
5
6
7
for {
	c,e:=l.Accept()
	if e != nil {
		panic(e)
	}
	go s.process(c)
} }

func New(c cache.Cache) *Server{ return &Server{c} }

func (s *Server) readKey(r *bufio.Reader) (string, error) { klen, e:=readlen(r) if e != nil { return ““,e } key :=make([]byte, klen) _,e = io.ReadFull(r,k)

1
2
3
4
if e != nil {
	return "", e
}
return string(key), nil }

func (s *Server) readKeyAndValue(r *bufio.Reader) (string, []byte,error){ klen,e:=s.readlen(r) if e != nil { return ““,nil,e }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
vlen, e:=s.readlen(r)
if e != nil {
	return "",nil,e
}

k :=make([]byte,klen)
_,e=io.ReadFull(r,k)
if e != nil {
	return "",nil,e
}

v:=make([]byte,vlen)
_,e=io.ReadFull(r,v)
if e != nil {
	return "",nil,e
}

return string(k),v,nil

}

func readlen(r *bufio.Reader) (int, error) { tmp, e:=r.ReadString(‘ ‘) if e != nil { return 0,e }

1
2
3
4
5
6
l,e:=strconv.Atoi(strings.TrimSpace(tmp))
if e != nil {
	return 0,e
}

return l,nil }

func sendResponse(value []byte, err error, conn net.Conn) error { if err != nil { errStr := err.Error() tmp :=fmt.Sprintf(“-%d”, len(errString) + errStr) _, e:=conn.Write(append([]byte(tmp)) return e } vlen :=fmt.Sprintf(“%d “, len(value)) _, e :=conn.Write(append([]byte(vlen),value…)) return e }

func (s *Server) set(conn net.Conn, r *bufio.Reader) error { k,v,e :=s.readKeyAndValue(r) if e != nil { return e } return sendResponse(nil,s.Set(k,v),conn) }

func (s *Server) del(conn net.Conn, r *bufio.Reader) error { k,e := s.readKey(r) if e != nil { return e } return sendResponse(nil,s.Del(k), conn) }

func (s *Server) process(conn net.Conn){ defer conn.Close() r:=bufio.NewReader(conn) for { op, e :=r.ReadByte() if e != nil { if e !=io.EOF { log.Println(“close connection due to error”, e) return } } if op == ‘S’{ e = s.set(conn,r) }else if op == ‘G’ { e=s.get(conn,r) }else if op == ‘D’{ e =s.del(conn,r) }else { log.Println(“close connection due to invalid operation:”, op) return }

1
2
3
4
5
	if e != nil {
		log.Println("close connection due to error:", e)
		return 
	}
} } /* Server 结构体内嵌一个cache.Cache 接口。它的Listen 方法调用Go 语言net 包 的Listen 函数监听本机TCP 的12346 端口,并在一个无限循环中接受客户端的连 接并调用Server.process 处理这个连接。处理连接的Server.process 方法运行在一个 新的goroutine 上,所以原来的goroutine 可以立刻继续执行,监听新的请求。 Server. process 方法的相关实现 */ ```