Go语言实现广播式并发聊天服务器
type Client struct {C chan string //用于发送数据的管道Name string //用户名Addr string //网络地址}保存在线用户的map表
var onlineMap map[string]Client消息通道
var message = make(chan string)
listener, err := net.Listen( tcp , 127.0.0.1:8000 )当客户端有消息发送,就向当前用户列表中所有在线用户转发消息go Manager()接受客户端的请求conn, err1 := listener.Accept()处理用户连接go HandleConn(conn)func main() {//监听listener, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen.err=", err)return}defer listener.Close()//新开一个协程,转发消息,只要有消息,就遍历map,给每个成员发送消息go Manager()//主协程,循环阻塞等待用户连接for {conn, err1 := listener.Accept()if err1 != nil {fmt.Println("listener.Accept.err1=", err1)continue}//处理用户连接go HandleConn(conn)}}
cliAddr := conn.RemoteAddr().String()创建一个用户结构体,默认:用户名和网络地址一样cli := Client{make(chan string), cliAddr, cliAddr},加入map表给客户端发送信息go WriteMsgToClient(cli, conn)广播某个人在线message - MakeMsg(cli, login )提示当前用户 cli.C - MakeMsg(cli, I am here )判断用户状态isQuit hasData接收用户的请求,查看当前用户who,改名rename,发送消息messagefunc HandleConn(conn net.Conn) {cliAddr := conn.RemoteAddr().String()cli := Client{make(chan string), cliAddr, cliAddr}//把结构体添加到maponlineMap[cliAddr] = cli//新开一个协程,给客户端发送信息go WriteMsgToClient(cli, conn)//广播某个人在线message - MakeMsg(cli, "login")//提示当前用户cli.C - MakeMsg(cli, "I am here")isQuit := make(chan bool) //对方是否主动退出hasData := make(chan bool) //对方是否有数据//新开一个协程,接收用户的请求go func() {buf := make([]byte, 2048)for {n, err := conn.Read(buf)if n == 0 {//对方断开或者出问题isQuit - truefmt.Println("conn.Read.err=", err)return}msg := string(buf[:n-1])if len(msg) == 3 msg == "who" {//遍历map,给当前用户发送所有成员conn.Write([]byte("user list:\n"))for _, tmp := range onlineMap {msg := tmp.Addr + ":" + tmp.Name + "\n"conn.Write([]byte(msg))}} else if len(msg) = 8 msg[:6] == "rename" {name := strings.Split(msg, "|")[1]cli.Name = nameonlineMap[cliAddr] = cliconn.Write([]byte("rename ok\n"))} else {message - MakeMsg(cli, msg)}hasData - true //代表有数据}}()for {//通过select检测channel的流动select {case -isQuit:delete(onlineMap, cliAddr) //当前用户从map移除message - MakeMsg(cli, "login out") //广播谁下线了returncase -hasData:case -time.After(60 * time.Second):delete(onlineMap, cliAddr)message - MakeMsg(cli, "time out leave out")return}}}
func WriteMsgToClient(cli Client, conn net.Conn) {for msg := range cli.C {conn.Write([]byte(msg + "\n"))}}
func MakeMsg(cli Client, msg string) (buf string) {buf = "[" + cli.Addr + "]" + cli.Name + ":" + msgreturn}
有消息到来就进行广播
给map分配空间onlineMap = make(map[string]Client)遍历在线用户列表,转发消息;没有消息之前message通道会阻塞func Manager() {//给map分配空间onlineMap = make(map[string]Client)for {msg := -message //没有消息前,会阻塞for _, cli := range onlineMap {cli.C - msg}}}
Go语言实现广播式并发聊天服务器