Github ウェアハウス:https://github.com/xuehu96/go-tcpcat (Welcome Star)
国内ウェアハウス:https://gitee.com/xuehu96/go-tcpcat
TCP は IoT データ サーバーやゲーム サーバーなどでよく使用され、通常は独自形式のプロトコルです。go
-tcpcat は、非常に少ないコードで TCP の透過的な送信とメッセージ処理機能を実現できます。
メッセージ処理は Go 言語をサポートしています。プライベート プロトコルを転送するためのフックです。パーサーインジェクションフレームワーク、Luaスクリプト処理、PythonGRPC呼び出し処理、HTTPコールバック処理、Redisキャッシュデータなど
インストール:
go get -u github.com/xuehu96/go-tcpcat
1. フック
ドッグ関数はコールバック関数です。指定されたイベントが発生した後、フレームワークは事前に挿入された処理関数をコールバックします。デフォルト
の処理関数はログを通じて出力します。ドッグ関数を設定すると、デフォルトの処理関数がオーバーライドされます。
プログラムは次のドッグサブ関数を設定します。
針 | 通話のタイミング | 使用例 |
---|---|---|
オンリッスン | リッスンが成功した後のコールバック | プログラムの開始 新しいリソース |
受け入れない | 新しいクライアント接続呼び出し | クライアントのソースを決定し、クライアントの数を制限する |
OnReadData | クライアントデータ呼び出しを受信しました | データ形式を決定し、先頭と末尾を削除します。 |
OnFnCode | データから関数コードを解析する | ファンクションコードとカスタムファンクション処理関数 |
データ送信時 | クライアントにデータを送信した後に呼び出されます | 送信が成功したかどうかを判断し、再送信するか、発信者に通知します。 |
閉じる時 | クライアントの開始後または切断後に呼び出されます | 切断後にクライアントに通知またはオフラインのマークを付ける |
オンストップ | Listen が閉じられた後に呼び出されます | リソースをクリーンアップする |
犬の使い方:
var fnc1 server.OnXXXXXX = func(param) ret{
// TODO
}
var fnc2 server.OnYYYYYY = func(param) ret{
// TODO
}
...
hooks := server.Hook{
OnXXXXXX: fnc,
OnYYYYYY: fnc,
...
}
s := server.New(
server.WithHook(hooks),
...
)
2. ファンクションコードとカスタムファンクション処理関数
HTTPルーティングと同様に、プライベートプロトコルにおけるデータパケットの処理方法を区別する機能コードを一般にファンクションコードと呼びます。
ファンクションコード解析機能OnFnCode
(データからファンクションコードを解析)
var fnc server.OnFnCode = func(buf []byte) string {
s := string(buf)
if strings.Contains(s, "ping") {
return "A"
}
if s[0] == 'B' {
return "B"
}
return ""
}
hooks := server.Hook{
OnFnCode: fnc,
}
対応する関数コードを処理する関数(ルーティングと同様)
s.AddFn("A", func(c *server.Client, code string, buf []byte, len int) {
// TODO
})
s.AddFn("B", func(c *server.Client, code string, buf []byte, len int) {
// TODO
})
3. ピンポン TCP サーバーの例
クライアントは接続後、データをサーバーに送信し、サーバーは次の形式でデータを処理します。
- 「ピン」は「ポン」と答えます
- 「time」は現在のサーバー時間を返します
- 「exit」サーバーはアクティブに切断されました
- クライアントが応答せずに他の形式を送信する
package main
import (
"context"
"github.com/xuehu96/go-tcpcat/pkg/logger"
"github.com/xuehu96/go-tcpcat/server"
"log"
"net"
"os"
"os/signal"
"strings"
"syscall"
"time"
)
func main() {
// 创建TCPListener
ln, err := net.Listen("tcp", ":9677")
if err != nil {
log.Fatalln(err.Error())
return
}
// 自定义如何从数据包中获取获取功能码
var fnc server.OnFnCode = func(buf []byte) string {
s := string(buf)
if strings.Contains(s, "ping") {
return "p"
}
if strings.Contains(s, "time") {
return "t"
}
if strings.Contains(s, "exit") {
return "x"
}
return ""
}
hooks := server.Hook{
OnFnCode: fnc,
}
// 创建TCP服务实例
s := server.New(
server.WithHook(hooks),
server.WithListener(ln),
server.WithLogger(logger.DebugLogger()),
)
// 添加功能码对应的处理函数 类似于HTTP的路由
s.AddFn("p", func(c *server.Client, code string, data []byte) {
c.ReplyData([]byte("pong"))
})
s.AddFn("t", func(c *server.Client, code string, data []byte) {
currentTime := time.Now()
c.ReplyData([]byte(currentTime.Format("2006-01-02 15:04:05.000000000")))
})
s.AddFn("x", func(c *server.Client, code string, data []byte) {
c.Close()
})
// Ctrl-C 结束
go func() {
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
<-signalCh
s.Stop(context.Background())
}()
// TCP服务器开始干活
s.Serve()
}