要是可以这样就好了,但是不行,得自己想办法。

select {
    case nread, err := conn.Read(buf):
}

  初步的框架是这样的,conn 读取的内容通过 chan 发送到 select。但是因为 chan 只能在发送端关闭,所以我们需要一个 chan 来通知 conn 的读取函数。

select {
    case <- time.After(timeout):
        // timeout logic
    case clientData := <-clientRx:
        // client logic
}

  那么代码就变成了这样,通过 defer 来保证代码不会忘记执行。readClientConn 函数把读取到的数据通过 clientRx 发送回来。

done := make(chan struct{})
go readClientConn(clientConn, done)
defer func() {
    done <- struct{}{}
    close(done)
}()
select {
    case <- time.After(timeout):
        // timeout logic
    case clientData := <-clientRx:
        // client logic
}

  readClientConn 大概的逻辑是这样,用上 select 是因为上面的函数可能已经退出了,要避免阻塞。还有一些细节,比如 clientTx 发送的内容中不应该只包含 buf,还应该有 err,同时 conn 要设置读取超时,退出的时候应该关闭 clientTx。

func readClientConn() {
    nread, err := conn.Read(buf)

    select {
        case clientTx <- buf:
        case <-done:
    }
}