~~~
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 作為結束符,確保數據包的結束。
*/
//白名單
~~~
- 目錄
- 第一例 gRPC使用例子
- 第二例 基于go-micro做服務注冊和服務發現
- 第三例 留言板項目源碼
- 第四例 聊天室
- 第五例 工具庫
- dao
- common
- common.go
- config
- config.go
- gorm
- grom.go
- sqlx
- sqlx.go
- kafka
- kafka.go
- log
- log.go
- log2.go
- redis
- redis.go
- zookeeper
- zookeeper.go
- init
- main.go
- 工具庫
- cache
- cfg.go
- redis
- 示例
- database
- cfg.go
- gorm.go
- sql.go
- 示例
- mq
- cfg.go
- kafka_consumer.go
- kafka_producter.go
- 示例
- time
- time.go
- 第六例 原生sql操作
- 第七例 sqlx操作
- 第八例 Redis數據庫(gomodule/redigo)
- 第九例 Redis消息隊列
- 第十例 Redis集群連接
- 十一例 Zookeeper操作
- 十二例 Kafka操作
- 十三例 NSQ操作
- 十四例 二分查找
- 十五例 交換排序 - 冒泡排序
- 十六例 插入排序 - 直接插入排序
- 十七例 插入排序 - 希爾排序
- 十八例 交換排序 - 快速排序
- 十九例 算法求解應用
- 二十例 pprof性能分析
- 二一例 CPU信息采集
- 二二例 Heap信息采集
- 二三例 Http信息采集
- 二四例 單元測試(功能測試)
- 二五例 基準測試(壓力測試/性能測試)
- 二六例 gdb調試
- 二七例 json序列化和反序列化
- 二八例 protobuf序列化和反序列化
- 二九例 包管理工具 go vendor
- 三十例 包管理工具 go mod
- 三一例 zip壓縮
- 三二例 交叉編譯
- 三三例 線上環境部署
- 三四例 業務:實現固定周期維護
- 三五例 聊天室(精簡版)
- 三六例 并發安全字典
- 三七例 導出Excel表格
- 三八例 導出CSV表格
- 三九例 聊天室(高并發)
- 四十例 JWT (Json Web Token)
- 四一例 雪花算法生成 Id
- 四二例 對稱加密 AES
- 四三例 非對稱加密 RSA
- 四四例 簽名算法 SHA1
- 四五例 數據庫操作 gorm
- gorm V2
- 四六例 數據庫操作 gorm 集合
- 數據庫連接和創建表
- 查詢 - 分頁
- 查詢所有數據
- 查詢單條數據
- 插入一條或多條數據
- 更新一條或多條數據
- 更新一條或多條數據(有零值)
- 四七例 RSA(MD5WithRSA 算法)簽名和驗簽方式
- 四八例 線上部署腳本
- 四九例 Elasticsearch
- 五十例 對象池
- 五一例 中間庫(github.com/wong-winnie/library)
- 五二例 二維碼(生成和解析)
- 五三例 回調用例
- 五四例 文件服務器(MINIO)
- 五五例 chm文檔轉json
- 提取內容頁Json
- 將目錄索引和內容頁混合生成Json
- 目錄層級小案例
- 五六例 部署 gogs 代碼管理工具
- 五七例 通過命令行操作SVN
- 五八例 根據數據庫表生產模型
- 五九例 Trie樹
- 六十例 二進制排序
- 六一例 遞歸+迭代實現無限級分類
- 六二例 Arrow 數據結構
- 簡單介紹
- Go 用Arrow數據格式與其它語言交互
- 六三例 LMDB 內存映射型數據庫
- 獲取指定Key位置
- 六四例 切片數據按字段分類
- 六五例 Xorm 批量插入數據
- 六六例 FlatBuffers 序列化和反序列化
- FlatBuffers 步驟1
- FlatBuffers 步驟2
- 六七例 數據同步
- 增量同步v1
- 全量同步v1
- 定時器
- 六八例 Http請求
- 六九例 Gin + 數據庫操作
- 七十例 ClickHouse 列式數據庫
- 七一例 用圖表展示數據庫數據
- 七二例 go:linkname
- 七三例 四舍五入、保留3小數位
- 七四例 判斷兩個時間戳是否同一天
- 七五例 Gin Http請求
- 七六例 過濾器
- 七七例 Excel 導入導出
- 七八例 小程序向公眾號推消息
- 七九列 解析二進制數據
- 例子一
- 例子二
- 八十例 路由轉發
- 八一例 協程池(安全執行任務,捕獲異常)
- 八二例 切片 slice
- 八三例 集合 map
- 八四例 Redis 六種數據類型
- 八五例 Zstd壓縮
- 八六例 提高接口并發量
- 八七例 協程 goroutine 和 通道 channel
- 八七例 Mysql 事務和索引等
- 編寫中
- 數據交互
- mysql 索引和事務
- 發請求
- defer
- 其它
- linux
- OAuth2.0 和 JWT
- 其它2
- 其他
- Web3.0 智能合約
- 多人貪吃蛇
- V1
- 客戶端
- 服務端
- V2
- 同步方式
- 游戲框架
- deepseek
- k8s
- TRPC
- Kafka
- 加密
- mm
- 技術擴展閱讀