【问题标题】:Simple Message Client golang简单消息客户端 golang
【发布时间】:2017-11-05 00:30:24
【问题描述】:

所以我开始了一个项目,其中涉及模块通过 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!

非常感谢任何想法。提前谢谢你。

【问题讨论】:

    标签: go stdout stdin


    【解决方案1】:

    这似乎是 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()
        }
    
    }
    

    编辑: 根据 cmets 的说法,这段代码显示了这个想法有什么问题。当您写一些东西并且不按 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{}{}
        }
    
    }
    

    【讨论】:

    • 嗯好的。目前无法对其进行测试,但看起来 client2 只能在您发送消息后输出。我会考虑这个想法。
    • 我不认为终端/控制台不适合异步IO操作。替代解决方案是 ncurses 或 termbox..
    • 我在想,在我的情况下,接收消息的可能性比发送消息的可能性大得多,我可能只有一个用于获取消息的终端程序,然后是另一个用于发送消息的程序。感谢您的努力。我确实看过术语框,但感觉好像付出了很多努力才不是一个大问题。
    • 应该是“我不认为终端/控制台适合异步IO操作”。您还可以看到更新的答案..
    猜你喜欢
    • 1970-01-01
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 2019-04-08
    • 2012-11-02
    • 2014-11-01
    • 1970-01-01
    相关资源
    最近更新 更多