duanchun5520 2016-06-28 20:07 采纳率: 0%
浏览 123
已采纳

Golang-将两条Reader返回的行用于select语句

For a simple golang chat/telnet client, I want to pass strings received from two bufio Readers to a select statement, so I can either send the user input to the server, or print the server sent data.

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

The compiler gives me back this error

select case must be receive, send or assign recv

I suspect I should be using channels. But

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('
')
    i, _ := connReader.ReadString('
')
    outgoing <- o
    incoming <- i

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

But the code doesn't accept or receive data. Finally, I suspect I should be using two go routines to check for the Reader return value?

  • 写回答

1条回答 默认 最新

  • doutangtan6386 2016-06-28 20:20
    关注

    You need to run them in goroutines or they can't simultaneously occur:

    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('
    ')
            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('
    ')
            if err != nil {
                fmt.Printf("incoming error: %v", err)
                return
            }
            incoming <- i
        }
    }()
    
    for {
        select {
        case out := <-outgoing:
            fmt.Print("> ")
            fmt.Fprintf(conn, out+"
    ")
        case in := <-incoming:
            fmt.Print(in)
        }
    }
    

    Edit

    To further elaborate: your first example won't work because select requires each case to be either a channel read or channel send operation, and the function call bufio.Reader.ReadString() is neither.

    Your second example won't work because the line outgoing <- o will block indefinitely. It is trying to send o over the channel outgoing, but outgoing is not buffered, and nothing is listening on it. Furthermore, since neither ReadString() call will return until a line is read, your for loop will only proceed once a line is read from BOTH readers in turn (and will then block on the channel send).

    That's why you need each Reader to have its own goroutine, so each can independently read off its Reader as input allows, and store it to the relevant channel as lines are read, and your select statement can then react to each line as it comes in from the individual goroutines.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向