Skip to content

Instantly share code, notes, and snippets.

@Kuri-su
Forked from xialeistudio/scanner.go
Last active May 20, 2019 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kuri-su/774314066a589990bab66f0bd5fc3e8f to your computer and use it in GitHub Desktop.
Save Kuri-su/774314066a589990bab66f0bd5fc3e8f to your computer and use it in GitHub Desktop.
Golang实现自定义TCP协议
package main
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
)
type Package struct {
Version [2]int8
Length int16
Data []byte
}
func (p *Package) String() string {
return fmt.Sprintf("Version:%d Length:%d Data:%s", p.Version, p.Length, p.Data)
}
// 打包
func (p *Package) Pack(writer io.Writer) {
binary.Write(writer, binary.BigEndian, p.Version)
binary.Write(writer, binary.BigEndian, p.Length)
binary.Write(writer, binary.BigEndian, p.Data)
}
// 解包
func (p *Package) Unpack(r io.Reader) {
binary.Read(r, binary.BigEndian, &p.Version)
binary.Read(r, binary.BigEndian, &p.Length)
if p.Length > 0 {
p.Data = make([]byte, p.Length)
}
binary.Read(r, binary.BigEndian, &p.Data)
}
func main() {
pkg := &Package{
Version: [2]int8{'V', 1},
Data: []byte("ABCDEFGHIJK"),
}
pkg.Length = int16(len(pkg.Data))
buf := new(bytes.Buffer)
pkg.Pack(buf)
pkg.Pack(buf)
pkg.Pack(buf)
// scanner
scanner := bufio.NewScanner(buf)
scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
if !atEOF && data[0] == 'V' {
if len(data) > 4 { // 2字节版本号+2字节数据长度,最少4字节
length := int16(0) // 数据包长度
binary.Read(bytes.NewReader(data[2:4]), binary.BigEndian, &length) // 第3-4字节为数据包长度
if int(length)+4 <= len(data) { // 数据已经读完了,但是产生了粘包现象
return int(length) + 4, data[:int(length)+4], nil
}
}
}
return
})
for scanner.Scan() {
pack := new(Package)
pack.Unpack(bytes.NewReader(scanner.Bytes()))
fmt.Println(pkg)
}
if err := scanner.Err(); err != nil {
fmt.Printf("error:%s", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment