kcp 協議的 Golang 實現庫
kcp-go 是 Golang 實現的 kcp 協議庫,它是可靠的 UDP 庫。
該庫 kcp-go 旨在通過 UDP 數據包提供流暢、有彈性、有序、經過錯誤檢查和匿名的流傳遞。該庫和開源項目 kcptun 經過了戰鬥測試。從低端 MIPS 路由器到高端服務器,數以百萬計的設備在各種應用中部署了基於 kcp-go 驅動的程序。包括在線遊戲、直播、文件同步和網絡加速。
我們介紹一下 kcp 協議,kcp 協議是一種快速可靠的 ARQ 協議,它以比 TCP 浪費 10%~20% 的帶寬爲代價,換取平均延遲降低 30%~40%,且最大延遲降低三倍的傳輸效果。它是純算法實現,並不負責底層協議(如 UDP)的收發,需要使用者自己定義下層數據包的發送方式,以 callback 的方式提供給 KCP。時鐘也是外部提供,內部不會有任何一次系統調用。KCP 協議已經通過使用 C 語言實現,整個協議只包含 ikcp.h,ikcp.c 兩個源文件,可以方便的集成到用戶自己的協議棧中。更多 kcp 內容請參考 kcp Github 項目(https://github.com/skywind3000/kcp)。
kcp-go 項目的特性:
-
專爲對延遲敏感的場景而設計。
-
緩存友好和內存優化的設計,提供極高性能的核心。
-
在單個商用服務器上能夠處理 > 5K 併發連接。
-
與 net.Conn 和 net.Listener 兼容,可以替代 net.TCPConn。
-
Reed-Solomon 碼支持 FEC(前向糾錯)。
-
在 CFB 模式下,支持 AES、TEA、3DES、Blowfish、Cast5、Salsa20 等數據包級加密,生成完全匿名的數據包。
-
爲整個服務器應用程序只創建固定數量的 goroutine,並考慮了 goroutines 之間上下文切換的成本。
-
與 skywind3000 的 C 版本兼容,並進行了各種改進。
-
依賴於平臺的優化:Linux 利用了 sendmmsg 和 recvmmsg。
kcp-go 規格:
kcp-go 簡單使用,回聲示例:
package main
import (
"crypto/sha1"
"io"
"log"
"time"
"github.com/xtaci/kcp-go/v5"
"golang.org/x/crypto/pbkdf2"
)
func main() {
key := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New)
block, _ := kcp.NewAESBlockCrypt(key)
if listener, err := kcp.ListenWithOptions("127.0.0.1:12345", block, 10, 3); err == nil {
// spin-up the client
go client()
for {
s, err := listener.AcceptKCP()
if err != nil {
log.Fatal(err)
}
go handleEcho(s)
}
} else {
log.Fatal(err)
}
}
// handleEcho send back everything it received
func handleEcho(conn *kcp.UDPSession) {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if err != nil {
log.Println(err)
return
}
n, err = conn.Write(buf[:n])
if err != nil {
log.Println(err)
return
}
}
}
func client() {
key := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New)
block, _ := kcp.NewAESBlockCrypt(key)
// wait for server to become ready
time.Sleep(time.Second)
// dial to the echo server
if sess, err := kcp.DialWithOptions("127.0.0.1:12345", block, 10, 3); err == nil {
for {
data := time.Now().String()
buf := make([]byte, len(data))
log.Println("sent:", data)
if _, err := sess.Write([]byte(data)); err == nil {
// read back the data
if _, err := io.ReadFull(sess, buf); err == nil {
log.Println("recv:", string(buf))
} else {
log.Fatal(err)
}
} else {
log.Fatal(err)
}
time.Sleep(time.Second)
}
} else {
log.Fatal(err)
}
}
TCP 中的 SYN/FIN/RST 等控制消息在 KCP 中沒有定義。您需要在應用程序級別使用保活 / 心跳機制。一個真實的例子是在會話上使用多路複用協議,例如 smux(它具有嵌入式保活機制)。
更多內容,請參考 Github 地址:
https://github.com/xtaci/kcp-go
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/yPkbVfozaTNdlXcaLE9-SA