2017-06-03 8 views
2

私はWebSocket経由でサーバからメッセージを送受信するモジュールを含むプロジェクトを開始しました。しかし、私はモジュールとやり取りしてメッセージを送るための簡単な方法が必要でした。簡単なメッセージクライアントgolang

私はプログラムをgoroutineで私のメッセージを要求します。私はenterを押すとメッセージを送り、別のメッセージを求めます。メインのgoroutineでは、メッセージを受け取るまで待つことになります。メッセージが来たら、現在の行を上書きし、前の行を新しい行に置き換えます。

ただし、問題は1つのみです。私の入力を新しい行に配置する方法を知らない。次の例のテストでは、改行文字を受け取るまでos.Stdin.Readが停止するようです。

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
    "time" 
) 

func main() { 
    // Input Buffer 
    var msg string 

    scanner := bufio.NewScanner(os.Stdin) 
    scanner.Split(bufio.ScanBytes) 

    go func() { 
     for { 
      // Prompt the user for a message 
      fmt.Print("client1: ") 

      // Scan os.Stdin, splitting on bytes 
      for scanner.Scan() { 
       if scanner.Text() == "\n" { 
        break 
       } else { 
        // If the character is not \n, add to the input buffer 
        msg += scanner.Text() 
       } 
      } 

      // Do something with the input buffer then clear it 
      fmt.Println(msg) 
      msg = "" 
     } 
    }() 

    for { 
     select { 
     // Receive a message from a client 
     case <-time.After(5 * time.Second): 
      // Write the message over the current line 
      fmt.Println("\rclient2: Hello") 

      // Prompt the user again for their message 
      // proving the current input buffer 
      fmt.Print("client1: " + msg) 
     } 
    } 
} 

出力例:任意のアイデアが大幅に高く評価されている

client1: Hello! 
Hello! 
client2: Hello 
client1: Bye! 
Bye! 
client2: Hello 
client2: Hello // Was "client1: Good " before being overwritten 
client1: Bye! 
Good Bye! 

。進んでいただきありがとうございます。

答えて

0

IO競合状態のようです。あなたのゴルーチンはmainと同期されていません。 Btw ScanLinesも同じことをします。このことを考えてみましょう:

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
) 

func main() { 
    scanner := bufio.NewScanner(os.Stdin) 
    msgQ := make(chan string) 

    defer close(msgQ) 

    go func() { 
     for { 
      // Prompt the user for a message 
      fmt.Print("client1: ") 
      msg, ok := <-msgQ 
      if !ok { 
       return 
      } 
      fmt.Println("\rclient1 said: " + msg) 
      // Write the message over the current line 
      fmt.Println("client2: Hello") 
     } 
    }() 


    // Scan os.Stdin, splitting on bytes 
    for scanner.Scan() { 
     msgQ <- scanner.Text() 
    } 

} 

EDIT:コメントによると、このコードはその考えが間違っているかを示しています。何かを書いてENTERを押すと、client2は現在の行を上書きします。現在の行を保存(CTRL-U)して復元(CTRL-Y)することはできますが、ANSI署名またはSignalをプログラムで呼び出すことはできません。

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
    "time" 
) 

func main() { 

    scanner := bufio.NewScanner(os.Stdin) 
    sendQ := make(chan struct{}) 

    defer close(sendQ) 

    //simulate local client1 console 
    go func() { 
     for { 
      fmt.Print("client1: ") 
      select { 
      case _, ok := <-sendQ: 
       if !ok { 
        return 
       } 
      case <-time.After(5 * time.Second): 
       fmt.Printf("\r\033[K") // delete current line from right 
       fmt.Println("client2: Hello") 
      } 
     } 
    }() 

    for scanner.Scan() { 
     sendQ <- struct{}{} 
    } 

} 
+0

Hmm ok。現時点ではテストすることはできませんが、メッセージを送信した後にのみclient2が出力できるように見えます。私はそのアイデアを持って遊びます。 –

+0

私は端末/コンソールが非同期IO操作には適していないとは思わない。別の解決策は、ncursesまたはtermbox .. – bigless

+0

私の状況では、メッセージは送信されるよりも受信される可能性が高いと思っている、私はちょうどメッセージを送信するための別のプログラムを取得するための単一のターミナルプログラムがあります。あなたの努力に感謝します。私はtermboxを見ましたが、巨大な問題ではなく、多くの努力のように感じます。 –