我有以下代码实现了一个用go编写的简单tcp聊天服务器。我无法理解代码中通过"合作伙伴渠道"发送连接的位置。我看到当第一个用户连接时,select语句只等到下一个用户加入。但是当第二个用户加入时,代码如何通过通道发送信息并知道选择哪种情况?
package main
import (
"io"
"net"
"log"
"fmt"
)
const listnAddr = "localhost:4000"
func main(){
l , err := net.Listen("tcp",listnAddr)
if err != nil {
log.Fatal(err)
}
for {
c , err := l.Accept()
if c!= nil{
fmt.Printf("ok")
}
if err != nil {
log.Fatal(err)
}
go match(c)
}
}
var partner = make(chan io.ReadWriteCloser)
func match(c io.ReadWriteCloser){
fmt.Fprint(c,"waiting for a partner...")
select{
case partner <- c:
//now handled by the other goroutine
case p := <-partner:
chat(p,c)
}
fmt.Printf("waiting")
}
func chat(a, b io.ReadWriteCloser) {
fmt.Fprintln(a, "Found one! Say hi.")
fmt.Fprintln(b, "Found one! Say hi.")
go io.Copy(a, b)
io.Copy(b, a)
}
&#13;
答案 0 :(得分:2)
var partner = make(chan io.ReadWriteCloser)
func match(c io.ReadWriteCloser) {
fmt.Fprint(c, "waiting for a partner...")
select {
case partner <- c:
//now handled by the other goroutine
case p := <-partner:
chat(p, c)
}
fmt.Printf("waiting")
}
每次客户端连接时,都会调用一次匹配函数。我相信很清楚。
select语句的第一种情况是想在伙伴通道下发送TCP连接。第二种情况是希望从合作伙伴渠道接收TCP连接。
如果select语句的多个案例已准备就绪,the runtime picks one at random。
当第一次调用匹配时(让我们调用这个M1),两种情况都不能继续,因为通道是无缓冲的; M1阻止并等待。当第二次调用匹配(M2)时,接下来究竟发生了什么实际上是不可预测的,但效果是相同的。
假设M2尝试继续第一种情况,将第二种连接发送给伙伴。这将有效,因为M1已准备好接收它。所以M2继续第一种情况,M1继续第二种情况并调用chat
。
现在让我们回过头来假设M2尝试继续第二种情况,从合作伙伴处接收另一个连接。这也有效,因为M1已准备好发送第一个连接。因此,在这种情况下,M1继续第一种情况,M2继续第二种情况并调用chat
。
因此在两种情况下都会调用chat,但参数的顺序不是确定性的。在这种情况下,它可以以任何方式工作,因为沟通是双向的,我们不关心谁先来。
然后它又重新开始。