You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
2.3 KiB
Go
118 lines
2.3 KiB
Go
1 year ago
|
package protocol
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
"git.noahlan.cn/noahlan/nnet/packet"
|
||
|
"git.noahlan.cn/noahlan/ntool/nlog"
|
||
|
)
|
||
|
|
||
|
type TCPPackerOption func(*TCPPacker)
|
||
|
|
||
|
type TCPPacker struct {
|
||
|
buf *bytes.Buffer
|
||
|
header *TCPHeader
|
||
|
size int // 最近一次读取的 body size
|
||
|
byteOrder binary.ByteOrder
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
tcpHeadLength = 2 + 2 + 2
|
||
|
tcpMaxPacketSize = 64 * 1024
|
||
|
)
|
||
|
|
||
|
func NewTCPPacker(byteOrder binary.ByteOrder) *TCPPacker {
|
||
|
p := &TCPPacker{
|
||
|
buf: bytes.NewBuffer(nil),
|
||
|
byteOrder: byteOrder,
|
||
|
}
|
||
|
|
||
|
p.resetFlags()
|
||
|
|
||
|
return p
|
||
|
}
|
||
|
|
||
|
func (d *TCPPacker) resetFlags() {
|
||
|
d.header = nil
|
||
|
d.size = -1
|
||
|
}
|
||
|
|
||
|
func (d *TCPPacker) Pack(header interface{}, data []byte) ([]byte, error) {
|
||
|
tcpHeader, ok := header.(*TCPHeader)
|
||
|
if !ok {
|
||
|
return nil, packet.ErrWrongPacketType
|
||
|
}
|
||
|
bs := make([]byte, 8)
|
||
|
d.byteOrder.PutUint16(bs[0:2], tcpHeader.TransactionIdentifier)
|
||
|
d.byteOrder.PutUint16(bs[2:4], tcpHeader.ProtocolIdentifier)
|
||
|
d.byteOrder.PutUint16(bs[4:6], uint16(2+len(data)))
|
||
|
bs[6] = tcpHeader.Address
|
||
|
bs[7] = tcpHeader.Function
|
||
|
bs = append(bs, data...)
|
||
|
return bs, nil
|
||
|
}
|
||
|
|
||
|
func (d *TCPPacker) Unpack(data []byte) ([]packet.IPacket, error) {
|
||
|
d.buf.Write(data)
|
||
|
|
||
|
nlog.Debugf("接收TCP数据: %x", data)
|
||
|
var (
|
||
|
packets []packet.IPacket
|
||
|
err error
|
||
|
)
|
||
|
|
||
|
if d.buf.Len() < 9 {
|
||
|
return packets, fmt.Errorf("TCP Frame error: packet less than 9 bytes")
|
||
|
}
|
||
|
|
||
|
if d.size < 0 {
|
||
|
if err = d.readHeader(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (d.size - 2) <= d.buf.Len() {
|
||
|
p := NewTCPPacket()
|
||
|
p.TCPHeader = d.header
|
||
|
p.Data = d.buf.Next(d.size - 2)
|
||
|
|
||
|
packets = append(packets, p)
|
||
|
|
||
|
if d.buf.Len() < (tcpHeadLength + 2) {
|
||
|
d.resetFlags()
|
||
|
break
|
||
|
}
|
||
|
|
||
|
if err = d.readHeader(); err != nil {
|
||
|
return packets, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if packets == nil || len(packets) == 0 {
|
||
|
d.resetFlags()
|
||
|
d.buf.Reset()
|
||
|
}
|
||
|
|
||
|
return packets, err
|
||
|
}
|
||
|
|
||
|
func (d *TCPPacker) readHeader() error {
|
||
|
header := d.buf.Next(tcpHeadLength + 2)
|
||
|
d.header = &TCPHeader{
|
||
|
TransactionIdentifier: d.byteOrder.Uint16(header[0:2]),
|
||
|
ProtocolIdentifier: d.byteOrder.Uint16(header[2:4]),
|
||
|
Length: d.byteOrder.Uint16(header[4:6]),
|
||
|
ModbusHeader: ModbusHeader{
|
||
|
Address: header[6],
|
||
|
Function: header[7],
|
||
|
},
|
||
|
}
|
||
|
d.size = int(d.header.Length)
|
||
|
// 最大包限定
|
||
|
if d.size > tcpMaxPacketSize {
|
||
|
return packet.ErrPacketSizeExceed
|
||
|
}
|
||
|
return nil
|
||
|
}
|