一、思路
定义好3个通道 entering,leaving,massages分别为登录,登出(单向输入通道)和信息(双向通道)。
开启两个协程,一个协程负责监听通道是否有输入或输出,一个协程负责组织发送的内容和流程的控制 演示地址(http://main.cladmining.top)
二、具体代码加详细说明
package Controller
import (
"bufio"
"fmt"
"log"
"net"
)
//聊天室
func MassagesStart(){
listener, err := net.Listen("tcp", "localhost:8099")
if err != nil {
log.Fatal(err)
}
go broadcaster() //这里需要先消费chan里面的值 会阻塞
for {
conn, err := listener.Accept() //等待并且返回下一个监听到的链接
if err != nil {
log.Print(err)
continue
}
go handleConn(conn) //往通道里面写值
}
}
type client chan<- string
//定义三个通道
var (
entering =make(chan client) //登入的通道
leaving =make(chan client) //离开的通道
massages=make(chan string) //发送消息的童道
)
func broadcaster() {
clients:=make(map[client]bool)
for {
select {
case msg:=<-massages: //有消息进来的时候循环去发送消息
for cli:=range clients{
cli<-msg
}
case cli:=<-leaving://关闭客户端的时候
delete(clients,cli)
close(cli)
case cli:=<-entering:
clients[cli]=true
}
}
}
func handleConn(conn net.Conn) {
ch:=make(chan string) //定义一个字符串传输通道
go clientWriter(conn,ch) //起一个协程顺着通道往链接里面发字符串
who:=conn.RemoteAddr().String() //把地址转成字符串
ch<-"you are a pig,your address is:"+who
massages<- who+":are login"
entering<-ch
input:=bufio.NewScanner(conn)
for input.Scan() { //逐行扫描
massages<-who+":"+input.Text()
}
leaving<-ch //chan 存入或取出的时候会阻塞ch里面有值 当你关闭链接的时候 leaving读取到的是一个空字符串 然后程序往下执行
massages<-who+":has leaving"
conn.Close()
}
func clientWriter(conn net.Conn,ch chan string) {
for msg:=range ch{
fmt.Fprintln(conn,msg) //与fmt.println相比较多了一个往conn写的操作
}
}
三、注意事项
通道的阻塞,select的应用tcp连接间的通信。展示图片