Skip to content

Instantly share code, notes, and snippets.

@SLonger
Last active May 13, 2019 02:37
Show Gist options
  • Save SLonger/a136ffc0f5b4caa50559f1435753602c to your computer and use it in GitHub Desktop.
Save SLonger/a136ffc0f5b4caa50559f1435753602c to your computer and use it in GitHub Desktop.
tcp 粘包处理 client
// 参考链接https://feixiao.github.io/2016/05/08/bufio/
package main
import (
"bufio"
"bytes"
"encoding/binary"
"flag"
"fmt"
"io"
"net"
"os"
"strconv"
)
var host = flag.String("host", "localhost", "The hostname or IP to connect to; defaults to \"localhost\".")
var port = flag.Int("port", 8000, "The port to connect to; defaults to 8000.")
// 自定义协议的组包和拆包
type Package struct {
Version [2]int8
Datalen int64
Data []byte
}
func (p *Package) String() string {
return fmt.Sprintf("Version:%d DataLen:%d Data:%s",
p.Version, p.Datalen, p.Data)
}
func (p *Package) Pack(w io.Writer) {
binary.Write(w, binary.BigEndian, p.Version)
binary.Write(w, binary.BigEndian, p.Datalen)
binary.Write(w, binary.BigEndian, p.Data)
}
func (p *Package) Unpack(r io.Reader) {
binary.Read(r, binary.BigEndian, &p.Version)
binary.Read(r, binary.BigEndian, &p.Datalen)
if p.Datalen > 0 {
p.Data = make([]byte, p.Datalen)
}
binary.Read(r, binary.BigEndian, &p.Data)
}
func main() {
flag.Parse()
dest := *host + ":" + strconv.Itoa(*port)
fmt.Printf("Connecting to %s...\n", dest)
conn, err := net.Dial("tcp", dest)
if err != nil {
if _, t := err.(*net.OpError); t {
fmt.Println("Some problem connecting.")
} else {
fmt.Println("Unknown error: " + err.Error())
}
os.Exit(1)
}
readConnection(conn)
}
func readConnection(conn net.Conn) {
scanner := bufio.NewScanner(conn)
// 数据的分离规则,根据协议自定义
//设置分离函数
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
if !atEOF && bytes.Equal(data[:2], []byte("V1")) {
if len(data) > 10 {
var dataLen int64
binary.Read(bytes.NewReader(data[2:10]), binary.BigEndian, &dataLen)
if int(dataLen)+10 <= len(data) {
token = data[int64(10) : int64(10)+int64(dataLen)]
return int(dataLen) + 10, token, nil
}
}
}
return
}
scanner.Split(split)
for {
for scanner.Scan() {
//fmt.Println(string(scanner.Text())
fmt.Println(scanner.Bytes())
}
if err := scanner.Err(); err != nil {
fmt.Printf("Invalid input: %s", err)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment