golang聊天服务器/ select语句

时间:2018-04-11 20:36:00

标签: go channel goroutine

我有以下代码实现了一个用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;
&#13;
&#13;

1 个答案:

答案 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,但参数的顺序不是确定性的。在这种情况下,它可以以任何方式工作,因为沟通是双向的,我们不关心谁先来。

然后它又重新开始。