2017-12-01 5 views
2

GoサーバーにTCPソケット設定があります。私は着信接続を受け入れ、forループを実行し、net.Conn.Read関数を使用して着信データを読み取ります。永続的なTCPソケットにnet.Conn.Readを使用する正しい方法は何ですか

しかし、それは私には意味がありません。メッセージサイズの返品を続けるために完全なメッセージが受信されたことをどのように知っていますか?

これは、現在、私のコードです:

func (tcpSocket *TCPServer) HandleConnection(conn net.Conn) { 

    println("Handling connection! ", conn.RemoteAddr().String(), " connected!")  
    recieveBuffer := make([]byte, 50) // largest message we ever get is 50 bytes 

    defer func() {   
     fmt.Println("Closing connection for: ", conn.RemoteAddr().String()) 
     conn.Close() 
    }() 

    for { 
     // how does it know the end of a message vs the start of a new one? 
     messageSize, err := conn.Read(recieveBuffer) 
     if err != nil { 
      return 
     } 
     if messageSize > 0 { // update keep alive since we got a message 
      conn.SetReadDeadline(time.Now().Add(time.Second * 5))  
     } 
    } 
} 

は、私のアプリケーションは、長い6バイト(任意のサイズにすることができます)でメッセージを送るとしましょう。 conn.Readは、そのメッセージの終わりを受信したときに、そのメッセージの続きをどのように知りますか?

私の経験は主にC#にあるので、ここでは珍しいです。私のC#アプリケーションでは、メッセージは最初のバイトに含まれるメッセージのサイズを持っています。その後、forループを使用して残りのバイトをメッセージサイズまで読み込みます。

しかし、上記のコードは完全なメッセージを受け取っているように見えますが、メッセージのサイズは自動的にどのように知るのですか?

私は実際これがどうやって起こっているのか、それとも私が実際に間違っていると運がうまくいっているのか混乱しています。

私のすべてのメッセージには、メッセージのサイズを示す最初のバイトのヘッダーがあります。しかし、それは私がGoサーバ上でそれを必要としないようだ、私は誤解どのようにこれは動作しますか?

+0

TCPは言語に関係なく同じです。メッセージの境界を正しく処理するかどうかはあなた次第です。 – JimB

+0

だからこそ、すべての例でRead(someBuffer)を使用するのはなぜですか?あなたが境界を伝えることができない場合、いつ読書が使われるでしょうか?私はそれを実際に正しく行う方法の例を見つけることができません。 – WDUK

+0

私はTCP接続から他にどのように読むと思いますか?それがTCPが動作する方法です。ストリームプロトコルであり、単にメッセージの概念はありません。何らかのメッセージエンベロープが必要な場合は、より高いレベルのプロトコルを使用します。 – JimB

答えて

3

TCPはメッセージフレーミングを提供しません。ストリームをバッファして、定義したプロトコルに従ってメッセージを解析するのはあなた次第です。

TCPストリームを解析するときには、接続をすぐにbufio.Readerにラップすると便利です。なぜなら、より効率的に読むことができるだけでなく、より便利な方法を提供できるからです。プロトコルを解析する方法の例は次のとおりです。

buff := make([]byte, 50) 
c := bufio.NewReader(conn) 

for { 
    // read a single byte which contains the message length 
    size, err := c.ReadByte() 
    if err != nil { 
     return err 
    } 

    // read the full message, or return an error 
    _, err := io.ReadFull(c, buff[:int(size)]) 
    if err != nil { 
     return err 
    } 

    fmt.Printf("received %x\n", buff[:int(size)]) 
} 
+0

ああ、それは私が探していたように見えます!ありがとうございました :) – WDUK

関連する問題