2017-06-03 52 views
2

所以我開始了一個項目,它涉及模塊通過websockets從服務器發送和接收消息。不過,我想要一個簡單的方式來交互並向模塊發送消息。簡單消息客戶端golang

所以我有程序要求我在goroutine中的消息,當我按下回車鍵時,它發送消息並提示我換另一個消息。在主要的goroutine中,它將等待,直到它收到一條消息,然後當它結束時,寫上當前行並將新行上的內容替換掉。

但是,只有一個問題。它不知道如何讓我的投入放在新的線上。在我用下面的例子進行的測試中,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競爭條件。你的goroutine沒有與main同步。順便說一句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() 
    } 

} 

編輯:根據意見,這個代碼顯示了什麼是錯的這一想法。當你寫東西而不按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

嗯好的。目前無法進行測試,但看起來client2只能在發送消息後才能輸出。我會玩這個想法。 –

+0

我不認爲終端/控制檯不適合異步IO操作。替代解決方案是ncurses或者termbox .. – bigless

+0

我在想我的情況,消息比發送消息更有可能被接收,我可能只有一個終端程序獲取消息,然後是另一個發送它們的程序。感謝您的努力。我確實看過termbox,但是對於一個沒有太大問題的人來說,這是一個很大的努力。 –