~~~ package main import ( "bytes" "encoding/binary" "fmt" "github.com/klauspost/compress/zstd" "log" ) var ( /* 但凡是涉及到多字节的数值(整数、浮点数等)时,通常都需要明确字节序(如 uint16、uint32、int64、float64 等) 数值在二进制存储和传输时确实需要指定字节序(大端或小端),因为不同的系统可能采用不同的字节序 大端字节序:高位字节放在前面,低位字节放在后面 小端字节序:低位字节放在前面,高位字节放在后面 */ byteOrder = binary.BigEndian //全局缓冲区 buffer []byte maxBufferSize = 10 * 1024 * 1024 // 增加 buffer 的最大大小限制,防止内存泄露 ) // 压缩数据 func ZSTDEncoder(data []byte) []byte { var buf bytes.Buffer encoder, err := zstd.NewWriter(&buf) if err != nil { return nil } defer encoder.Close() _, err = encoder.Write(data) if err != nil { return nil } err = encoder.Close() if err != nil { return nil } return buf.Bytes() } // 解压数据 func ZSTDDecoder(data []byte) ([]byte, error) { decoder, err := zstd.NewReader(nil) if err != nil { return nil, err } defer decoder.Close() decompressedData, err := decoder.DecodeAll(data, nil) if err != nil { return nil, err } return decompressedData, nil } // 创建数据包(4字节数据长度 + 数据 + 1字节结束符OxFF) func createPacket(data []byte) []byte { var buf bytes.Buffer // 压缩数据 compressedData := ZSTDEncoder(data) //4字节数据长度 length := uint32(len(compressedData)) err := binary.Write(&buf, byteOrder, length) if err != nil { log.Fatal(err) } // 数据(压缩后的数据) buf.Write(compressedData) // 1字节结束符OxFF buf.WriteByte(0xFF) return buf.Bytes() } // 解析数据包 func sendPacket(packet []byte) { // 追加数据到全局缓冲区 if packet != nil { buffer = append(buffer, packet...) if len(buffer) > maxBufferSize { fmt.Println("buffer长度溢出, 清除缓冲区") buffer = nil return } } // 解析数据包 for { // 需要至少 5 字节数据(4 字节长度 + 1 字节结束符) if len(buffer) < 5 { break } // 读取长度字段(4 字节) var length uint32 err := binary.Read(bytes.NewReader(buffer[:4]), byteOrder, &length) if err != nil { break // 数据不足,等待更多数据 } // 计算完整数据包的长度 expectedLength := 4 + int(length) + 1 if len(buffer) < expectedLength { break // 数据不足,等待更多数据 } // 读取数据部分 compressedData := buffer[4 : 4+length] // 检查结束符(0xFF) if buffer[expectedLength-1] != 0xFF { fmt.Println("错误的结束符, 丢弃损坏的数据包") // **从当前 buffer 中查找下一个可能的正确数据包** found := false for i := 1; i < len(buffer)-4; i++ { if buffer[i] == 0xFF { buffer = buffer[i+1:] // 丢弃错误数据,继续解析 found = true break } } if !found { buffer = nil // 没有找到新的起点,清空 buffer } continue } // 解压数据 data, err := ZSTDDecoder(compressedData) if err != nil { fmt.Println("Error: Failed to decompress data, discarding corrupted packet") buffer = buffer[expectedLength:] // 丢弃错误数据 continue } // 打印解析结果 fmt.Println("Parsed Data:", string(data)) // 移除已解析的数据 buffer = buffer[expectedLength:] } } func main() { // 原始数据 data := []byte("Hello, World!") packet := createPacket(data) fmt.Println("----------------------模拟半包-------------------------") packet1 := packet[0:3] packet2 := packet[3:8] packet3 := packet[8:] sendPacket(packet1) sendPacket(packet2) sendPacket(packet3) fmt.Println("----------------------模拟粘包-------------------------") combinedPacket := append(packet, packet...) combinedPacket = append(combinedPacket, packet...) sendPacket(combinedPacket) fmt.Println("----------------------模拟数据损坏或丢包-------------------------") badPacket := append(createPacket([]byte("Corrupt Data")), 0x00) // 添加错误的结尾 sendPacket(badPacket) sendPacket(packet) sendPacket(packet) sendPacket(packet) } //RSA算法(非对称加密算法) //全局 buffer 并发不安全,需要 sync.Mutex 或 channel 解决竞争问题 //1.对压缩数据中的 0xFF 进行转义 给出对于的代码 或这个改成数据校验 //2.问题:频繁的 append 和切片操作可能引发内存拷贝。改进:使用 bytes.Buffer 或预分配缓冲区 给出对应的代码 //如果你的数据量较大,建议优化 并发处理,比如: //生产者-消费者模型(goroutine + channel) //去掉 0xFF 结束符,直接用 [4字节长度] + 数据 解析 //[2字节协议版本][2字节消息类型][4字节数据长度][数据][2字节校验和][1字节结束符(0xFF)] //问题:数据在传输中可能损坏(如长度字段被篡改)。 //改进:在协议头或尾部加入校验字段(如 CRC32) //问题:频繁的 append 和切片操作可能引发内存拷贝。 //改进:使用 bytes.Buffer 或预分配缓冲区 /* 开始符(Start byte): 0xAA 作为开始符,表示数据包的开始,确保不会误解析。 数据长度(Length): 使用 4 字节存储数据(压缩数据)的长度。由于采用了大端字节序,跨平台时数据可以正确解析。 序列号(Sequence Number): 用 4 字节存储,每个数据包都带有一个递增的序列号,用来保证包的顺序性,防止乱序或重放攻击。 时间戳(Timestamp): 使用 8 字节存储 Unix 时间戳,表示数据包创建的时间,可以防止重放攻击(例如,如果数据包的时间戳超出一定范围,则认为是篡改的)。 消息认证码(MAC): 使用 HMAC-SHA256 对数据(包括数据长度、压缩数据、序列号、时间戳等)进行签名,确保数据包未被篡改。 HMAC 密钥由发送方与接收方共享。 压缩数据(Compressed Data): 将数据压缩后存储,减少数据传输大小。 结束符(End byte): 0xFF 作为结束符,确保数据包的结束。 */ //白名单 ~~~