永続的な TCP ソケットに対する net.Conn.Read の適切な使用法
Go では、永続的な TCP ソケットを操作するには、接続を確立し、継続的に行う必要があります。受信データを読み取ります。 net.Conn.Read 関数はソケットからデータを取得する役割を果たしますが、その動作はすぐには明確ではないかもしれません。
TCP のメッセージ フレームについて
一部とは異なります他のプロトコルとは異なり、TCP は本質的にメッセージ フレーミングを提供しません。これは、連続データ ストリーム内でメッセージを分離する方法を定義するのはアプリケーション次第であることを意味します。
ヘッダーを使用した従来のメッセージ フレーミング
以前の C# エクスペリエンスでは、メッセージの先頭には、メッセージ サイズを含むヘッダーが付加されていました。このアプローチにより、受信アプリケーションは後続のメッセージの正確な長さを知ることができます。
Go によるメッセージ処理方法
Go は別のアプローチを採用します。デフォルトでは、net.Conn.Read() にはメッセージの終わりを判断する固有のメカニズムがありません。質問で提供したコードスニペットは、メッセージ境界を考慮せずにループ内で conn.Read() を呼び出すだけです。これは特定のシナリオでは機能する可能性がありますが、信頼性やスケーラブルなソリューションではありません。
解決策: カスタム メッセージ フレーミング
永続的な TCP ソケットを適切に処理するには、以下を実装する必要があります。カスタムメッセージフレーム。これには、受信データをバッファリングし、独自に定義したプロトコルに従って解析することが含まれます。
bufio.Reader を使用した例
推奨されるアプローチの 1 つは、組み込みの bufio を使用することです。 net.Conn をラップする .Reader。このラッパーは追加機能を提供し、データの読み取りをより効率的にします。
import ( "bufio" "fmt" "io" "net" ) func main() { listener, err := net.Listen("tcp", ":8080") if err != nil { panic(err) } for { conn, err := listener.Accept() if err != nil { continue } go handleConnection(conn) } } func handleConnection(conn net.Conn) { defer conn.Close() r := bufio.NewReader(conn) for { size, err := r.ReadByte() if err != nil { return } buff := make([]byte, size) if _, err := io.ReadFull(r, buff); err != nil { return } fmt.Println("Received:", buff) } }
この例では、handleConnection 関数は最初に接続から後続のメッセージの長さを表す 1 バイトを読み取ります。次に、バッファを作成し、io.ReadFull を使用して、指定されたサイズのメッセージ全体を読み取ります。これにより、アプリケーションはさまざまな長さのメッセージをシームレスに処理できるようになります。
以上が永続的な TCP ソケットの Go で net.Conn.Read を使用してメッセージ フレーミングを確実に処理する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。