Zinx-V0.5 封包和拆包

Zinx-v0.5版本着重处理TCP粘包问题,通过消息封装模块和拆包封包模块来实现。消息封装包含属性如消息ID、内容和长度。在抽象层和实现层中,定义了相应的接口和结构体。同时,更新了request对象的接口、结构体和构造函数。在connection部分,改进了读取数据的方式,确保能够正确解析粘包情况,包括第一次读取的8个字节和后续根据数据长度读取内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Zinx-v0.5

为了解决tcp粘包问题

消息封装模块
属性
  1. 消息id
  2. 消息的内容
  3. 消息的长度
抽象层
type IMessage interface {
	//getter
	GetMsgId() uint32
	GetMsgLen() uint32
	GetMsgData() []byte
	
	//setter
	SetMsgId(uint32) 
	SetMsgLen(uint32) 
	SetMsgData([]byte) 
}
实现层
//
type Message struct {
	Id  uint32
	Datalen uint32
	Data []byte
}

func (m *Message) GetMsgId() uint32 {
	return m.Id
}
func (m *Message) GetMsgLen() uint32 {
	return m.Datalen
}
func (m *Message) GetMsgData() []byte {
	return m.Data
}

//setter
func (m *Message) SetMsgId(id uint32) {
	m.Id =id
}
func (m *Message) SetData(data []byte) {
	m.Data = data
}
func (m *Message) SetDatalen(len uint32) {
	m.Datalen = len
}
拆包封包模块
抽象层
type IDataPack interface {
	//获取二进制包的头部长度  固定返回8
	GetHeadLen() uint32

 	//封包方法  ---- 将 Message  打包成 |datalen|dataID|data|\
 	Pack(msg IMessage) ([]byte, error)

	//拆包方法  ---  将|datalen|dataID|data|   拆解到 Message 结构体中
	UnPack([]byte) (IMessage, error)
}
实现层
type DataPack struct {


}

//初始化一个DataPack对象
func NewDataPack() *DataPack {
	return &DataPack{}
}

//获取二进制包的头部长度  固定返回8
func (dp *DataPack) GetHeadLen() uint32 {
	//Datalen uint32(4字节) + ID uint32(4字节)
	return 8
}

//封包方法  ---- 将 Message  打包成 |datalen|dataID|data|\
func (dp *DataPack) Pack(msg ziface.IMessage) ([]byte, error) {
	//创建一个存放二进制的字节缓冲
	dataBuffer := bytes.NewBuffer([]byte{})

	//将datalen 写进buffer中
	if err := binary.Write(dataBuffer, binary.LittleEndian, msg.GetMsgLen()) ; err != nil {
		return nil, err
	}

	//将 dataID写进buffer中
	if err := binary.Write(dataBuffer, binary.LittleEndian, msg.GetMsgId()) ; err != nil {
		return nil, err
	}

	//将 data写进buffer中
	if err := binary.Write(dataBuffer, binary.LittleEndian, msg.GetMsgData()) ; err != nil {
		return nil, err
	}

	//返回这个缓冲
	return dataBuffer.Bytes(), nil
}

//拆包方法  ---  将|datalen|dataID|data|   拆解到 Message 结构体中
func (dp *DataPack) UnPack(binaryData []byte) (ziface.IMessage, error) {
	//解包的时候 是分2次解压,  第一次读取固定的长度8字节, 第二次是根据len 再次进行read
	msgHead := &Message{} //msgHead.Datalen, msgHead.dataID

	//创建一个 读取二进制数据流的io.Reader
	dataBuff := bytes.NewReader(binaryData)

	//将二进制流 先读datalen 放在msg的DataLen属性中
	if err := binary.Read(dataBuff, binary.LittleEndian, &msgHead.Datalen); err != nil {
		return nil, err
	}
	//将二进制流的  DataID 方在Msg的DataID属性中
	if err := binary.Read(dataBuff, binary.LittleEndian, &msgHead.Id); err != nil {
		return nil, err
	}

	return msgHead, nil
}
修改
修改request对象
接口
type IRequest interface {

	//得到当前请求的链接
	GetConnection() IConnection
	//得到消息
	GetMessage() IMessage
}

结构体
type request struct {
	//链接
	conn ziface.IConnection
	//消息
	msg ziface.IMessage
}
构造函数
//构造方法
func NewRequest(conn ziface.IConnection, msg ziface.IMessage) ziface.IRequest {
	r := &request{
		conn,
		msg,
	}
	return r
}
修改connection
读取数据,解决tcp粘包
  1. 第一次读取

    指定长度读取

    只读8个字节

  2. 第二次读取

    根据数据长度读取数据内容

func (c *Connection) startReader() {
	//从对端读数据
	fmt.Println("Reader go is startin....")
	defer fmt.Println("connID = ", c.connID, "Reader is exit, remote addr is = ", c.GetRemoteAddr().String())
	defer c.Stop()

	for {
		//创建拆包封包对象
		dp := new(DataPack)
		//读取客户端消息的头部
		msgHead := make([]byte, dp.GetHeadLen())

		_, err := io.ReadFull(c.GetTCPConnection(), msgHead)
		if err != nil {
			fmt.Println("read msg head error:", err)
			return
		}
		msg, err := dp.UnPack(msgHead)
		if err != nil {
			fmt.Println("unpack msg error:", err)
			return
		}
		//根据头部,获取数据的长度,读取消息的数据部分
		msgBody := make([]byte, msg.GetMsgLen())
		if _, err := io.ReadFull(c.GetTCPConnection(), msgBody); err != nil {
			fmt.Println("read msg body error:", err)
			return
		}
		msg.SetMsgData(msgBody)
		//将当前一次性得到的对端客户端请求的数据,封装成一个Request
		req := NewRequest(c, msg)

		//路由处理业务
		go func() {
			c.router.PreHandle(req)
			c.router.Handle(req)
			c.router.PostHandle(req)
		}()

		//将数据 传递给我们 定义好的Handle Callback方法
		//if err := c.handleAPI(req); err != nil {
		//	fmt.Println("ConnID", c.connID, "Handle is error", err)
		//	break
		//}
	}

}


func (c *Connection)Send(msgId uint32, msgData []byte) error {
	//判断链接是否结束
	if c.isClosed == true {
		return errors.New("connection is closed....")
	}

	dp := new(DataPack)
	//封装成msg
	binary, err := dp.Pack(NewMessage(msgId, msgData))
	if err != nil {
		fmt.Println("pack err msg id:", msgId)
		return err
	}

	//将binaryMsg发送给对端
	if _, err := c.GetTCPConnection().Write(binary); err != nil {
		fmt.Println("conn write err msg id:",msgId)
		return err
	}
	return nil
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值