go--实现多并发聊天服务器
Posted traditional
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go--实现多并发聊天服务器相关的知识,希望对你有一定的参考价值。
package main import ( "net" "fmt" "strings" "time" ) type client struct { C chan string //用户发送数据的管道 Name string //用户名 Addr string //网络地址 } //保存在线用户 var onlineMap map[string]client var message=make(chan string) //新开一个协程,转发消息,每当有消息过来,遍历map,给map的每个成员发送消息 func Manager(){ //给map分配空间 onlineMap = make(map[string]client) for { msg:=<-message//没有消息前,会阻塞 //遍历map给每个map成员发送消息 for _,cli:= range onlineMap{ cli.C <- msg } } } //专门用于广播某人上线 func MakeMsg(cli client,msg string)(buf string){ return cli.Addr+msg } func WriteMsgToClient(cli client,conn net.Conn) { for msg:=range cli.C{//给当前客户端发送信息 conn.Write([]byte(msg+" ")) } } func HandlerConn(conn net.Conn){ //处理用户连接 defer conn.Close() //获取客户端的网络地址 cliAddr:=conn.RemoteAddr().String() //创建一个结构体,默认用户名和网络地址一样 cli:=client{C:make(chan string),Name:cliAddr,Addr:cliAddr} //将该结构体添加到map成员当中 onlineMap[cliAddr]=cli //新开一个协程,专门给当前客户端发送信息 go WriteMsgToClient(cli,conn) //广播某人上线了 message <- MakeMsg(cli,"上线了") //提示,我是谁 cli.C<- "我是"+cli.Addr+",我上线了" //用户是否主动推出 isQuit:=make(chan bool) //对方是否有数据发送 hasData:=make(chan bool) //新建一个协程,接收用户发过来的数据 go func() { buf:=make([]byte,2048) for { n, err := conn.Read(buf) if n == 0 { //两种情况,对方断开连接,或者出问题 isQuit<-true //表示要主动退出了 fmt.Println("conn.Read error,err=", err) return } //window上会出现空格,因此把空格给去掉 msg := []byte(strings.TrimSpace(string(buf[:n]))) // 如果用户输入who,提示当前有哪些用户在线 if string(msg)=="who"{ //遍历map,给当前用户发送所有成员 for _,tem:=range onlineMap{ user_info:=tem.Addr+":"+tem.Name+" " conn.Write([]byte(user_info)) } }else if strings.Contains(string(msg),"rename|") && len(string(msg))>=8{ //让用户重新选择用户名 //rename|satori name:=strings.Split(string(msg),"|")[1] cli.Name=name onlineMap[cliAddr]=cli //提示用户改名成功 conn.Write([]byte("修改成功,您的名字已变为"+cli.Name+" ")) }else{ //转发此内容 message <- MakeMsg(cli, string(msg)) } hasData<-true } }() for { //通过select检测channel的流动 select{ case <- isQuit: delete(onlineMap,cliAddr)//将推出的用户从onlineMap当中移除 message<-MakeMsg(cli,"下线了")//广播某个人下线了 return case <- hasData: case <- time.After(10*time.Second): //超过10s不发言,会强制移除 delete(onlineMap,cliAddr) //将当前用户从map中移除 message<- MakeMsg(cli,"因为长时间未发言,已强制移除")//广播谁下线了 return } } } func main(){ //监听 listener,err:=net.Listen("tcp","192.168.1.35:8000") if err!=nil{ fmt.Println("listen error,err=",err) return } //关闭连接 defer listener.Close() //新开一个协程,转发消息,每当有消息过来,遍历map,给map的每个成员发送消息 go Manager() //主协程,循环阻塞等待用户连接 for{ conn,err:=listener.Accept() if err!=nil{ fmt.Println("accept error,err=",err) continue//出现错误,进行continue,处理下一个链接 } go HandlerConn(conn)//处理用户连接 } }
以上是关于go--实现多并发聊天服务器的主要内容,如果未能解决你的问题,请参考以下文章