问题
项目在经过思考后,重构了。主要重构原因有主要以下几点
1.包的设计粒度多大,导致依赖导致
2.代码gorouting操作不当,浪费cpu使用
3.网络模型使用不当,同步模型可以满足设计需求
4.select关键字使用不错,导致gorouting停止等待
重构后
修改协议设计,添加缓冲区,将网络和协议耦合降低。设计协议类,尽量以结构体为单位去做操作方法。
import (
"bytes"
"encoding/binary"
)
const (
MsgLength = 4
)
type Protocol struct {
msgBuf []byte
}
func New() *Protocol {
pro := &Protocol{msgBuf: make([]byte, 0)}
return pro
}
func (pro *Protocol) PushStream(buf []byte) {
pro.msgBuf = append(pro.msgBuf, buf...)
}
func (pro *Protocol) Enpack(message []byte) []byte {
Header := IntToBytes(len(message))
return append(Header, message...)
}
func (pro *Protocol) Depack() []string {
Msg := make([]string, 0)
buffer := pro.msgBuf
BufLen := len(pro.msgBuf)
i := 0
for i < BufLen {
if BufLen < i+MsgLength {
break
}
msgLen := BytesToInt(buffer[i : i+MsgLength])
if msgLen > 0 && msgLen < 2<<32 {
if BufLen < i+MsgLength+msgLen {
break
}
data := buffer[i+MsgLength : i+MsgLength+msgLen]
Msg = append(Msg, string(data))
i += MsgLength + msgLen
}
}
if i == BufLen {
pro.msgBuf = make([]byte, 0)
} else {
pro.msgBuf = buffer[i:]
}
return Msg
}
func IntToBytes(n int) []byte {
x := int32(n)
bytesBuffer := bytes.NewBuffer([]byte{})
binary.Write(bytesBuffer, binary.BigEndian, x)
return bytesBuffer.Bytes()
}
func BytesToInt(b []byte) int {
bytesBuffer := bytes.NewBuffer(b)
var x int32
binary.Read(bytesBuffer, binary.BigEndian, &x)
return int(x)
}
重构了网络操作,取代主函数,所有操作归并到网络类;更改接收和发送异步方式为同步操作。主要原因异步存在发送积压,导致客户端接收超时。
package server
import (
"EchoTCP/config"
"EchoTCP/logger"
"EchoTCP/protocol"
"net"
"time"
)
//Config 配置累
var Config = config.New(3)
//EchoServer 服务sock结构
type EchoServer struct {
Port string
IP string
Pro string
}
//Client 客户端
type Client struct {
conn net.Conn
tmpBuf protocol.Protocol
}
//New 创建新的EchoServer
func New() *EchoServer {
logger.Log.Logger.Info("Create EchoServer Sucesss")
Config.Dyn.Monitor()
return &EchoServer{}
}
//SetPort 设置端口号
func (server *EchoServer) SetPort(port string) {
server.Port = port
}
//SetAddr 设置IP地址
func (server *EchoServer) SetAddr(addr string) {
server.IP = addr
}
//SetPro 设置连接协议
func (server *EchoServer) SetPro(pro string) {
server.Pro = pro
}
//Listen 启动监听服务 返回监听对象 错误址
func (server *EchoServer) Listen() (listener net.Listener, err error) {
if server.IP == "" {
server.IP = Config.Sta.Sock.IP
}
if server.Port == "" {
server.Port = Config.Sta.Sock.Port
}
if "" == server.Pro {
server.Pro = Config.Sta.Sock.Protocol
}
addr := server.IP + ":" + server.Port
listener, err = net.Listen(server.Pro, addr)
logger.Log.Logger.Info(addr)
logger.Log.Logger.Info(server.Pro)
if err != nil {
logger.Log.Logger.Error(err.Error())
return nil, err
}
return listener, nil
}
//Accept 接受连接
func (server *EchoServer) Accept(listener net.Listener) {
for {
conn, err := listener.Accept()
if err != nil {
logger.Log.Logger.Error(err.Error())
continue
}
logger.Log.Logger.Info("There is Conner")
client := Client{conn, *protocol.New()}
go server.RecvHandle(client)
}
}
//RecvHandle 接受客户端发送过的消息
func (server *EchoServer) RecvHandle(client Client) {
buf := make([]byte, 1024)
defer client.conn.Close()
for {
client.conn.SetReadDeadline(time.Now().Add(time.Second * 10))
n, err := client.conn.Read(buf)
if err != nil {
if nerr, ok := err.(net.Error)
logger.Log.Logger.Info("client timeout")
} else {
logger.Log.Logger.Error(err.Error())
}
break
}
server.SendHandle(client, buf[:n])
}
}
//SendHandle 读写消息
func (server *EchoServer) SendHandle(client Client, buf []byte) {
client.tmpBuf.PushStream(buf)
recMsg := client.tmpBuf.Depack()
for _, msg := range recMsg {
logger.Log.Logger.Info(string("recv Msassge " + msg))
switch Config.Dyn.Opt.Select {
case 1:
msg = Reverse(msg)
default:
msg = Shuffle(msg)
}
_, err := server.SendSingleMsg(client.conn, msg)
if err != nil {
logger.Log.Logger.Error(err.Error())
}
logger.Log.Logger.Info(string("send msg : " + msg))
}
}
//SendSingleMsg 单条发送
func (server *EchoServer) SendSingleMsg(conn net.Conn, sendMsg string) (n int, err error) {
n, err = conn.Write([]byte(sendMsg))
return
}
修改针对配置的设计,把动态配置和静态配置合并一起,去掉冗余代码,封装一个配置管理类,通过传入参数分类实力化动态配置还是静态配置。
type opteration struct {
Select int
}
type dynConfig struct {
Opt opteration
Watcher *fsnotify.Watcher
}
type sock struct {
Port string
IP string
Protocol string
}
type def struct {
BufMax int
Timeout int
}
type staConfig struct {
Sock sock
Def def
}
type Config struct {
Sta *staConfig
Dyn *dynConfig
}
func New(configType int) (conf *Config) {
switch configType {
case 1:
conf = &Config{Sta: newStaticConfig()}
case 2:
conf = &Config{Dyn: newDynConfig()}
case 3:
conf = &Config{Sta: newStaticConfig(), Dyn: newDynConfig()}
}
return
}
func newStaticConfig() *staConfig {
var conf staConfig
if err := readFileConfig(&conf, staticFilePath); err != nil {
return nil
}
return &conf
}
func newDynConfig() *dynConfig {
var conf dynConfig
var err error
if err = readFileConfig(&conf, dynFilePath); err != nil {
return nil
}
conf.Watcher, err = fsnotify.NewWatcher()
if err != nil {
logger.Log.Logger.Error(err.Error())
return nil
}
err = conf.Watcher.Watch(dynFilePath)
if err != nil {
logger.Log.Logger.Error(err.Error())
return nil
}
return &conf
}
func readFileConfig(tlConfig interface{}, fileName string) (err error) {
if _, err = toml.DecodeFile(fileName, tlConfig); err != nil {
logger.Log.Logger.Error(err.Error())
return err
}
return nil
}
func (dyn *dynConfig) Monitor() {
go func() {
for {
select {
case <-dyn.Watcher.Event:
temp := newDynConfig()
if temp.Opt.Select != dyn.Opt.Select {
dyn.Opt = temp.Opt
}
logger.Log.Logger.Info(string("Change : " + fmt.Sprintf("%d", temp.Opt.Select)))
continue
case err := <-dyn.Watcher.Error:
logger.Log.Logger.Error(err.Error())
return
default:
time.Sleep(1 * time.Second)
}
}
}()
}
结束语
go语言的博大精深,设计理念由于没有具体的书籍很难学好。建议通过读go语言的源码,抛析源码学习使用go语言。
ps:项目暂时不给出,有需要可以私信我。