aceld
6 years ago
11 changed files with 386 additions and 54 deletions
-
27utils/globalobj.go
-
6ziface/iconnection.go
-
11ziface/idatapack.go
-
14ziface/imessage.go
-
1ziface/irequest.go
-
70znet/connection.go
-
71znet/datapack.go
-
107znet/datepack_test.go
-
46znet/message.go
-
9znet/request.go
-
4znet/server_test.go
@ -0,0 +1,11 @@ |
|||||
|
package ziface |
||||
|
|
||||
|
/* |
||||
|
封包数据和拆包数据 |
||||
|
直接面向TCP连接中的数据流,为传输数据添加头部信息,用于处理TCP粘包问题。 |
||||
|
*/ |
||||
|
type IDataPack interface{ |
||||
|
GetHeadLen() uint32 //获取包头长度方法
|
||||
|
Pack(msg IMessage)([]byte, error) //封包方法
|
||||
|
Unpack([]byte)(IMessage, error) //拆包方法
|
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
package ziface |
||||
|
|
||||
|
/* |
||||
|
将请求的一个消息封装到message中,定义抽象层接口 |
||||
|
*/ |
||||
|
type IMessage interface { |
||||
|
GetDataLen() uint32 //获取消息数据段长度
|
||||
|
GetMsgId() uint32 //获取消息ID
|
||||
|
GetData() []byte //获取消息内容
|
||||
|
|
||||
|
SetMsgId(uint32) //设计消息ID
|
||||
|
SetData([]byte) //设计消息内容
|
||||
|
SetDataLen(uint32) //设置消息数据段长度
|
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
package znet |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"encoding/binary" |
||||
|
"errors" |
||||
|
"zinx/utils" |
||||
|
"zinx/ziface" |
||||
|
) |
||||
|
|
||||
|
//封包拆包类实例,暂时不需要成员
|
||||
|
type DataPack struct {} |
||||
|
|
||||
|
//封包拆包实例初始化方法
|
||||
|
func NewDataPack() *DataPack { |
||||
|
return &DataPack{} |
||||
|
} |
||||
|
|
||||
|
//获取包头长度方法
|
||||
|
func(dp *DataPack) GetHeadLen() uint32 { |
||||
|
//Id uint32(4字节) + DataLen uint32(4字节)
|
||||
|
return 8 |
||||
|
} |
||||
|
//封包方法(压缩数据)
|
||||
|
func(dp *DataPack) Pack(msg ziface.IMessage)([]byte, error) { |
||||
|
//创建一个存放bytes字节的缓冲
|
||||
|
dataBuff := bytes.NewBuffer([]byte{}) |
||||
|
|
||||
|
//写msgID
|
||||
|
if err := binary.Write(dataBuff, binary.LittleEndian, msg.GetMsgId()); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
//写dataLen
|
||||
|
if err := binary.Write(dataBuff, binary.LittleEndian, msg.GetDataLen()); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
//写data数据
|
||||
|
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) { |
||||
|
//创建一个从输入二进制数据的ioReader
|
||||
|
dataBuff := bytes.NewReader(binaryData) |
||||
|
|
||||
|
//只解压head的信息,得到dataLen和msgID
|
||||
|
msg := &Message{} |
||||
|
|
||||
|
//读msgID
|
||||
|
if err := binary.Read(dataBuff, binary.LittleEndian, &msg.Id); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
//读dataLen
|
||||
|
if err := binary.Read(dataBuff, binary.LittleEndian, &msg.DataLen); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
//判断dataLen的长度是否超出我们允许的最大包长度
|
||||
|
if (utils.GlobalObject.MaxPacketSize > 0 && msg.DataLen > utils.GlobalObject.MaxPacketSize) { |
||||
|
return nil, errors.New("Too large msg data recieved") |
||||
|
} |
||||
|
|
||||
|
//这里只需要把head的数据拆包出来就可以了,然后再通过head的长度,再从conn读取一次数据
|
||||
|
return msg, nil |
||||
|
} |
@ -0,0 +1,107 @@ |
|||||
|
package znet |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"io" |
||||
|
"net" |
||||
|
"testing" |
||||
|
) |
||||
|
|
||||
|
//只是负责测试datapack拆包,封包功能
|
||||
|
func TestDataPack(t *testing.T) { |
||||
|
//创建socket TCP Server
|
||||
|
listener, err := net.Listen("tcp", "127.0.0.1:7777") |
||||
|
if err != nil{ |
||||
|
fmt.Println("server listen err:", err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//创建服务器gotoutine,负责从客户端goroutine读取粘包的数据,然后进行解析
|
||||
|
go func (){ |
||||
|
for{ |
||||
|
conn, err := listener.Accept() |
||||
|
if err != nil{ |
||||
|
fmt.Println("server accept err:", err) |
||||
|
} |
||||
|
|
||||
|
//处理客户端请求
|
||||
|
go func(conn net.Conn){ |
||||
|
//创建封包拆包对象dp
|
||||
|
dp := NewDataPack() |
||||
|
for{ |
||||
|
//1 先读出流中的head部分
|
||||
|
headData := make([]byte, dp.GetHeadLen()) |
||||
|
_, err := io.ReadFull(conn, headData) //ReadFull 会把msg填充满为止
|
||||
|
if err != nil { |
||||
|
fmt.Println("read head error") |
||||
|
} |
||||
|
//将headData字节流 拆包到msg中
|
||||
|
msgHead,err := dp.Unpack(headData) |
||||
|
if err != nil{ |
||||
|
fmt.Println("server unpack err:", err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if msgHead.GetDataLen() > 0 { |
||||
|
//msg 是有data数据的,需要再次读取data数据
|
||||
|
msg := msgHead.(*Message) |
||||
|
msg.Data = make([]byte, msg.GetDataLen()) |
||||
|
|
||||
|
//根据dataLen从io中读取字节流
|
||||
|
_, err := io.ReadFull(conn, msg.Data) |
||||
|
if err != nil { |
||||
|
fmt.Println("server unpack data err:", err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
fmt.Println("==> Recv Msg: ID=", msg.Id, ", len=", msg.DataLen, ", data=", string(msg.Data)) |
||||
|
} |
||||
|
} |
||||
|
}(conn) |
||||
|
|
||||
|
} |
||||
|
}() |
||||
|
|
||||
|
//客户端goroutine,负责模拟粘包的数据,然后进行发送
|
||||
|
conn, err := net.Dial("tcp", "127.0.0.1:7777") |
||||
|
if err != nil{ |
||||
|
fmt.Println("client dial err:", err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//创建一个封包对象 dp
|
||||
|
dp := NewDataPack() |
||||
|
|
||||
|
//封装一个msg1包
|
||||
|
msg1 := &Message{ |
||||
|
Id:0, |
||||
|
DataLen:5, |
||||
|
Data:[]byte{'h', 'e', 'l', 'l', 'o'}, |
||||
|
} |
||||
|
|
||||
|
sendData1, err := dp.Pack(msg1) |
||||
|
if err!= nil{ |
||||
|
fmt.Println("client pack msg1 err:", err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
msg2 := &Message{ |
||||
|
Id:1, |
||||
|
DataLen:7, |
||||
|
Data:[]byte{'w', 'o', 'r', 'l', 'd', '!', '!'}, |
||||
|
} |
||||
|
sendData2, err := dp.Pack(msg2) |
||||
|
if err!= nil{ |
||||
|
fmt.Println("client temp msg2 err:", err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//将sendData1,和 sendData2 拼接一起,组成粘包
|
||||
|
sendData1 = append(sendData1, sendData2...) |
||||
|
|
||||
|
//向服务器端写数据
|
||||
|
conn.Write(sendData1) |
||||
|
|
||||
|
//客户端阻塞
|
||||
|
select{} |
||||
|
} |
@ -0,0 +1,46 @@ |
|||||
|
package znet |
||||
|
|
||||
|
type Message struct { |
||||
|
Id uint32 //消息的ID
|
||||
|
DataLen uint32 //消息的长度
|
||||
|
Data []byte //消息的内容
|
||||
|
} |
||||
|
|
||||
|
//创建一个Message消息包
|
||||
|
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 |
||||
|
} |
||||
|
|
||||
|
//获取消息ID
|
||||
|
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 |
||||
|
} |
||||
|
|
||||
|
//设计消息ID
|
||||
|
func (msg *Message) SetMsgId(msgId uint32) { |
||||
|
msg.Id = msgId |
||||
|
} |
||||
|
|
||||
|
//设计消息内容
|
||||
|
func (msg *Message) SetData(data []byte) { |
||||
|
msg.Data = data |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue