Zinx-V0.5 封包和拆包

    xiaoxiao2023-11-18  152

    Zinx-v0.5

    为了解决tcp粘包问题

    消息封装模块
    属性
    消息id消息的内容消息的长度
    抽象层
    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粘包

    第一次读取

    指定长度读取

    只读8个字节

    第二次读取

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

    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 }
    最新回复(0)