所以我开始了一个涉及模块通过websockets从服务器发送和接收消息的项目。但是我想要一种简单的方法来交互并向模块发送消息。
所以我让程序在goroutine中询问我的消息,当我按下Enter键时,它会发送消息并提示我另一个消息。在主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 :(得分:0)
看起来像IO竞争条件。你的goroutine没有与主同步。 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()
}
}
编辑:根据评论,此代码显示了该想法的错误。当你写东西并且没有点击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{}{}
}
}