简单的消息客户端golang

时间:2017-06-03 21:00:01

标签: go stdout stdin

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

非常感谢任何想法。先谢谢你。

1 个答案:

答案 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{}{}
    }

}