2017-06-03 145 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,但是对于一个没有太大问题的人来说,这是一个很大的努力。 –