Golang - 为select语句使用两个Reader返回的行

时间:2016-06-28 20:07:06

标签: select go client chat

对于一个简单的golang聊天/ telnet客户端,我想将从两个bufio Readers接收的字符串传递给select语句,因此我可以将用户输入发送到服务器,或者打印服务器发送的数据。

conn, _ := net.Dial("tcp", "localhost:8998")
for {
    select{
    case line, _ := bufio.NewReader(os.Stdin).ReadString('\n'):
        fmt.Print("> ")
        fmt.Fprintf(conn, line + "\n")
    case data, _ := bufio.NewReader(conn).ReadString('\n'):
        fmt.Print(data)
    }
}

编译器给了我这个错误

select case must be receive, send or assign recv

我怀疑我应该使用频道。但是

conn, _ := net.Dial("tcp", "localhost:8998")
outgoing := make(chan string)
incoming := make(chan string)
for {
    inputReader := bufio.NewReader(os.Stdin)
    connReader := bufio.NewReader(conn)

    o, _ := inputReader.ReadString('\n')
    i, _ := connReader.ReadString('\n')
    outgoing <- o
    incoming <- i

    select{
    case out := <-outgoing:
        fmt.Print("> ")
        fmt.Fprintf(conn, out + "\n")
    case in := <-incoming:
        fmt.Print(in)
    }
}

但代码不接受或接收数据。最后,我怀疑我应该使用两个例程来检查Reader返回值?

1 个答案:

答案 0 :(得分:3)

您需要在goroutines中运行它们,否则它们无法同时发生:

conn, _ := net.Dial("tcp", "localhost:8998")

// Make outgoing reader routine
outgoing := make(chan string)
go func() {
    inputReader := bufio.NewReader(os.Stdin)
    for {
        o, _ := inputReader.ReadString('\n')
        if err != nil {
            fmt.Printf("outgoing error: %v", err)
            return
        }
        outgoing <- o
    }
}()

// Make incoming reader routine
incoming := make(chan string)
go func() {
    connReader := bufio.NewReader(conn)
    for {
        i, err := connReader.ReadString('\n')
        if err != nil {
            fmt.Printf("incoming error: %v", err)
            return
        }
        incoming <- i
    }
}()

for {
    select {
    case out := <-outgoing:
        fmt.Print("> ")
        fmt.Fprintf(conn, out+"\n")
    case in := <-incoming:
        fmt.Print(in)
    }
}

修改

进一步说明:你的第一个例子不起作用,因为select要求每个案例都是通道读取或通道发送操作,函数调用bufio.Reader.ReadString()都不是。

您的第二个示例无法正常工作,因为行outgoing <- o将无限期阻止。它正在尝试通过o发送outgoing,但outgoing未被缓冲,并且没有任何内容正在监听它。此外,由于在读取一行之前,ReadString()调用都不会返回,因此只有在依次从 BOTH 读取器读取一行时,for循环才会继续(然后将阻止在频道发送)。

这就是为什么你需要每个阅读器都有自己的goroutine,所以每个人都可以独立阅读其输入允许的阅读器,并在阅读行时将其存储到相关频道,并select然后声明可以对来自各个goroutines的每一行作出反应。