golang 自定义封包协议(转的)

jackluo · · 2475 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
package protocol
 
import (
    "bytes"
    "encoding/binary"
)
 
const (
    ConstHeader         = "jackluo"
    ConstHeaderLength   = 7
    ConstSaveDataLength = 4
)
 
//封包
func Packet(message []byte) []byte {
    return append(append([]byte(ConstHeader), IntToBytes(len(message))...), message...)
}
 
//解包
func Unpack(buffer []byte, readerChannel chan []byte) []byte {
    length := len(buffer)
 
    var i int
    for i = 0; i < length; i = i + 1 {
        if length < i+ConstHeaderLength+ConstSaveDataLength {
            break
        }
        if string(buffer[i:i+ConstHeaderLength]) == ConstHeader {
            messageLength := BytesToInt(buffer[i+ConstHeaderLength : i+ConstHeaderLength+ConstSaveDataLength])
            if length < i+ConstHeaderLength+ConstSaveDataLength+messageLength {
                break
            }
            data := buffer[i+ConstHeaderLength+ConstSaveDataLength : i+ConstHeaderLength+ConstSaveDataLength+messageLength]
            readerChannel <- data
 
            i += ConstHeaderLength + ConstSaveDataLength + messageLength - 1
        }
    }
 
    if i == length {
        return make([]byte, 0)
    }
    return buffer[i:]
}
 
//整形转换成字节
func IntToBytes(n int) []byte {
    x := int32(n)
 
    bytesBuffer := bytes.NewBuffer([]byte{})
    binary.Write(bytesBuffer, binary.BigEndian, x)
    return bytesBuffer.Bytes()
}
 
//字节转换成整形
func BytesToInt(b []byte) int {
    bytesBuffer := bytes.NewBuffer(b)
 
    var x int32
    binary.Read(bytesBuffer, binary.BigEndian, &x)
 
    return int(x)
}
package main

import (
    "fmt"
    "net"
    "os"
    "./protocol"
)

func main() {
    netListen, err := net.Listen("tcp", ":9988")
    CheckError(err)
 
    defer netListen.Close()
 
    Log("Waiting for clients")
    for {
        conn, err := netListen.Accept()
        if err != nil {
            continue
        }
 
        Log(conn.RemoteAddr().String(), " tcp connect success")
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
   
    //声明一个临时缓冲区,用来存储被截断的数据
    tmpBuffer := make([]byte, 0) 
    //声明一个管道用于接收解包的数据
    readerChannel := make(chan []byte, 16)
    go reader(readerChannel)

    buffer := make([]byte, 1024)
    for {
        n, err := conn.Read(buffer)
        if err != nil {
            Log(conn.RemoteAddr().String(), " connection error: ", err)
            return
        }
/*        Log(conn.RemoteAddr().String(), "receive data length:", n)
        Log(conn.RemoteAddr().String(), "receive data:", buffer[:n])
        Log(conn.RemoteAddr().String(), "receive data string:", string(buffer[:n]))
*/  
     tmpBuffer = protocol.Unpack(append(tmpBuffer, buffer[:n]...), readerChannel)  
    }
}
func reader(readerChannel chan []byte) {
    for {
        select {
        case data := <-readerChannel:
            Log(string(data))
        }
    }
}
func Log(v ...interface{}) {
    fmt.Println(v...)
}
 
func CheckError(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
}
package main
 
import (
    "fmt"
    "net"
    "os"
    "time"
    "./protocol"
)
 
func sender(conn net.Conn) {
    for i := 0; i < 100; i++ {
        words := "{\"Id\":1,\"Name\":\"golang\",\"Message\":\"message\"}"
        conn.Write(protocol.Packet([]byte(words)))
    }
     fmt.Println("send over")
}
 
func main() {
    server := "127.0.0.1:9988"
    tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
 
    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
 
    defer conn.Close()
 
    fmt.Println("connect success")
 
    go sender(conn)
 
    for {
        time.Sleep(1 * 1e9)
    }
}

 

本文来自:博客园

感谢作者:jackluo

查看原文:golang 自定义封包协议(转的)

入群交流(和以上内容无关):加入Go大咖交流群,免费领全套学习资料或添加微信:muxilin131420 备注:入群;或加QQ群:729884609

2475 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传