2017-02-09 5 views
0

私は個人的なプロジェクトとして単純なチャットサーバーを作って、ネットパッケージといくつかの並行性を学びます。私の第1のアイデアは、サーバがNCCコマンドecho -n "hello" | nc -w1 -4 localhost 2016 -p 61865を使用して送信されたものを印刷するようにすることです。しかし、最初の読書の後、私のコードは後続のメッセージを無視します。net connを使って読み続けるにはどうすればいいですか?

func (s *Server) messageReader(conn net.Conn) { 
defer conn.Close() 
buffer := make([]byte, 1024) 
for { 
    //read buff 
    blen, err := conn.Read(buffer) 
    if err != nil { 
     log.Fatal(err) 
    } 

    message := string(buffer[:blen]) 

    if message == "/quit" { 
     fmt.Println("quit command received. Bye.") 
     return 
    } 

    if blen > 0 { 
     fmt.Println(message) 
     buffer = buffer[:0] 
    } 
} 
} 

// Run Start up the server. Manages join and leave chat 
func (s *Server) Run() { 
// Listen on port TCP 2016 
listener, err := net.Listen("tcp", ":2016") 
if err != nil { 
    log.Fatal(err) 
} 
defer listener.Close() 

for { 
    //wait for connection 
    conn, err := listener.Accept() 
    if err != nil { 
     log.Fatal(err) 
    } 

    go s.messageReader(conn) 

} 
} 

新しいクライアントから新しいメッセージを送信すると問題なく印刷されますが、別のメッセージを送信した場合は何もしません。何が欠けていますか?私はConnをリセットするか、それを閉じて新しいものを生成する必要がありますか?

答えて

3

メッセージを印刷した後、bufferをゼロにスライスします。長さゼロのスライスにデータを読み込むことはできません。読取りバッファをまったく再スライスする必要はありません。

エラーをチェックする前に、読み込みバイトを処理する必要があります。これは、成功した読み取りでio.EOFが返されるためです。あなたが使用していないので、あなたはそれにもかかわらず注意すべき

defer conn.Close() 
buffer := make([]byte, 1024) 
for { 
    n, err := conn.Read(buffer) 
    message := string(buffer[:n]) 

    if message == "/quit" { 
     fmt.Println("quit command received. Bye.") 
     return 
    } 

    if n > 0 { 
     fmt.Println(message) 
    } 

    if err != nil { 
     log.Println(err) 
     return 
    } 
} 

:それはようos.Exit

作業messageReader体が見えるかもしれません呼び出すよう

あなたは、サーバーの読みループでlog.Fatalを使用しないでくださいここでフレーミングプロトコルの任意の並べ替え、各conn.Readが完全または単一のメッセージを返すことを保証することはできません。ストリーム内のメッセージを区切るためには、ある種の上位プロトコルが必要です。

+0

標準ライブラリ内でどのようなプロトコルをお勧めしますか? 'net/http'が動作する可能性がありますが、もし私が間違っていないなら、HTTPはメッセージングプロトコルではありません。私は範囲を小さく保つことを試みているが、私は何ができるか、それをどうやってやるべきかを学びたい。 あなたの答えに余分なビットありがとうございました。非常に有用な知識。 – cmejia

+0

@ cmejia:あなたのニーズに応じてプロトコルが異なります。最も一般的なフレーミング方法は、おそらく単純な長さ接頭文字列です。また、メッセージに表示されないようにする区切り文字を使用することもできます。 ['net/textproto'](https://golang.org/pkg/net/textproto/)には、行を区切るための' \ r \ n 'と '。\ r \ n'というドットエンコード形式が含まれていますメッセージの終わりをMIME形式のキー値とともに示します。 – JimB

関連する問題