代码节选与 GO语言圣经 这本书的案例,我在这里做注释和自己对代码的理解
type client chan<- string // send only channel
var (
entering = make(chan client)
leaving = make(chan client)
messages = make(chan string)
)
func main() {
listener,err := net.Listen("tcp","0.0.0.0:8888")
if err != nil {
log.Fatal(err)
}
go broadcaster()//单独起一个go开始广播监听(异步,函数内部不停的select监听各类消息)
for{//这里不停的监听新链接
conn,err := listener.Accept()
if err != nil {
fmt.Fprintf(os.Stdout,"you got something wrong %v",err)
continue
}
go handleConn(conn)//监听每一个链接上来的链接交由handleconn处理
}
}
func broadcaster() {
clients := make(map[client]bool)//all connected clients
for {
select {
case msg := <- messages:
for cli := range clients{
cli <- msg
}
case cli := <- entering:
clients[cli]= true//将新加入的链接存到clients里
case cli := <- leaving:
delete(clients,cli)close(cli)
}
}
}
func handleConn(conn net.Conn) {//每个客户端保证一个handleconn
ch := make(chan string)
go clientWriter(conn,ch)
who := conn.RemoteAddr().String()
ch <- "You are " + who messages <- who + " has joined us"//只要一有消息来就存到全局变量messages里面去开始广播欢迎消息
entering <- ch//将新chan存入entering这个特殊结构中
input := bufio.NewScanner(conn)for input.Scan() {//这里不停的接受该链接用户传递过来的消息
messages <- who + ": " + input.Text()//再次存入客户端输入的消息文本,广播函数再次收到信号
}
leaving <- ch//如果客户端关闭了标准输入,那么把队列离开写入leaving交给广播函数去删除这个客户端并关闭这个客户端。
//广播这个人的离开给所有人。
messages <- who + " has left "
conn.Close()
}
func clientWriter(conn net.Conn,ch <-chan string) {
for msg := range ch {
fmt.Fprintln(conn,msg)// NOTE: ignoring network errors
}
}
有疑问加站长微信联系(非本文作者)