Zinx-V0.5消息封装和处理tcp粘包
1.将Request中的data、len再进行封装,封装成一个message,其中包含id、data、len
1.1.抽象层ziface
type IMessage
interface {
GetDataLen() uint32
GetMsgId() uint32
GetData() []byte
SetMsgId(uint32)
SetData([]byte)
SetDataLen(uint32)
}
1.2.实现层znet
type Message
struct {
Id
uint32
DataLen
uint32
Data
[]byte
}
func NewMsgPackage(id
uint32, data
[]byte) *Message
{
return &Message
{
Id
: id
,
DataLen
: uint32(len(data
)),
Data
: data
,
}
}
func (msg
*Message
) GetDataLen() uint32 {
return msg
.DataLen
}
func (msg
*Message
) GetMsgId() uint32 {
return msg
.Id
}
func (msg
*Message
) GetData() []byte {
return msg
.Data
}
func (msg
*Message
) SetDataLen(len uint32) {
msg
.DataLen
= len
}
func (msg
*Message
) SetMsgId(msgId
uint32) {
msg
.Id
= msgId
}
func (msg
*Message
) SetData(data
[]byte) {
msg
.Data
= data
}
2.定义一个能解决tcp粘包问题的拆包封包模块
2.1.抽象层ziface
type IDataPack
interface{
GetHeadLen() uint32
Pack(msg IMessage
)([]byte, error)
Unpack([]byte)(IMessage
, error)
}
2.2.实现层znet
type DataPack
struct {}
func NewDataPack() *DataPack
{
return &DataPack
{}
}
func(dp
*DataPack
) GetHeadLen() uint32 {
return 8
}
func(dp
*DataPack
) Pack(msg ziface
.IMessage
)([]byte, error) {
dataBuff
:= bytes
.NewBuffer([]byte{})
if err
:= binary
.Write(dataBuff
, binary
.LittleEndian
, msg
.GetDataLen()); err
!= nil {
return nil, err
}
if err
:= binary
.Write(dataBuff
, binary
.LittleEndian
, msg
.GetMsgId()); err
!= nil {
return nil, err
}
if err
:= binary
.Write(dataBuff
, binary
.LittleEndian
, msg
.GetData()); err
!= nil {
return nil ,err
}
return dataBuff
.Bytes(), nil
}
func(dp
*DataPack
) Unpack(binaryData
[]byte)(ziface
.IMessage
, error) {
dataBuff
:= bytes
.NewReader(binaryData
)
msg
:= &Message
{}
if err
:= binary
.Read(dataBuff
, binary
.LittleEndian
, &msg
.DataLen
); err
!= nil {
return nil, err
}
if err
:= binary
.Read(dataBuff
, binary
.LittleEndian
, &msg
.Id
); err
!= nil {
return nil, err
}
if (utils
.GlobalObject
.MaxPacketSize
> 0 && msg
.DataLen
> utils
.GlobalObject
.MaxPacketSize
) {
return nil, errors
.New("Too large msg data recieved")
}
return msg
, nil
}
封包过程就是将一个message封装成一条[]byte类型的数据,其中前4字节是一个uint32类型数据,内容为data数据的len,后面4字节是一个uint32类型数据,内容为data数据的id。
拆包过程就是先读出数据的前8字节内容,代表了后面data的len和id,用这两数据返回一个message类型的对象,然后通过len来判断后面data的len,创建一个len长度的缓冲区,将一条完整的data读出,添加到message中,完成解读。
3.将上述两模块集成到zinx中
3.1改变Request的抽象层和实现层
type IRequest
interface {
GetConnection() IConnection
GetMsg() IMessage
}
type Request
struct {
conn ziface
.IConnection
msg ziface
.IMessage
}
func NewReqeust(conn ziface
.IConnection
, msg ziface
.IMessage
) ziface
.IRequest
{
req
:= &Request
{
conn
:conn
,
msg
:msg
,
}
return req
}
func(r
*Request
) GetConnection() ziface
.IConnection
{
return r
.conn
}
func(r
*Request
) GetMsg() ziface
.IMessage
{
return r
.msg
}
3.2将zinx读包 的机制,由之前的一次read,改成按照拆包机制, 读取两次
func (c
*Connection
) StartReader() {
......
for {
dp
:= NewDataPack()
headData
:= make([]byte, dp
.GetHeadLen())
if _, err
:= io
.ReadFull(c
.Conn
, headData
); err
!= nil {
fmt
.Println("read msg head error", err
)
break
}
msg
, err
:= dp
.UnPack(headData
)
if err
!= nil {
fmt
.Println("unpack error ", err
)
break
}
var data
[]byte
if msg
.GetMsgLen() > 0 {
data
= make([]byte, msg
.GetMsgLen())
if _, err
:= io
.ReadFull(c
.Conn
, data
); err
!= nil {
fmt
.Println("read msg data error ", err
)
break
}
}
msg
.SetData(data
)
req
:= NewReqeust(c
, msg
)
go func() {
c
.Router
.PreHandle(req
)
c
.Router
.Handle(req
)
c
.Router
.PostHandle(req
)
}()
}
}
3.3将zinx的发包机制, 有之前的write二进制,改成先封包,再发送
修改send方法
func (c
*Connection
) Send(msgId
uint32, msgData
[]byte) error {
if c
.isClosed
== true {
return errors
.New("Connection closed ..send Msg ")
}
dp
:= NewDataPack()
binaryMsg
, err
:= dp
.Pack(NewMsgPackage(msgId
, msgData
))
if err
!= nil {
fmt
.Println("Pack error msg id = ", msgId
)
return err
}
if _, err
:= c
.Conn
.Write(binaryMsg
); err
!= nil {
fmt
.Println("send buf error")
return err
}
return nil
}