golang group chat function

Original copy

package main

import (
	"fmt"
	"net"
	_ "net/http"
)


//首先实现用户上线的功能,最后是用户修改自己的名字
var(
	//用chan进行读取
	//alladdr = make(chan net.Addr,100)
	onlineMap  map[string]User
	//Message = make(chan map[net.Addr]User)
	Message = make(chan string)//发送的消息是字符串
)


type User struct {
	addr string
	name string
	c chan string//用户登录
	c1 chan string//用户退出
}

//还有两个功能,一个是修改自己的名称
//另一个是who之后返回所有

//最后是一个定时机制,就是超过10s没有连接通信的话就踢掉

//服务器处理客户端的通信事件//需要将用户存到map里面去
func handleConnect(conn net.Conn)  {
	remoteAdder := conn.RemoteAddr().String()
	user := User{remoteAdder,remoteAdder,make(chan string),make(chan string)}
	onlineMap[remoteAdder]=user//加入用户到map中,

	go connectWrite(user,conn)//这一个为什么可以触发全部的user,是每一个用户都会执行这一个协程

	go logoutlisten(user,conn)
	//需要将上线消息广播至全网
	//用户上线,那么该用户的chan就写入数据,然后需要有全局的一个管理者一直在监听每个用户的chan
	//然后从每个用户的chan中监听读,读到有消息而且是login的话就打印出来
	Message<-"["+remoteAdder+"]"+"login"
	go func() {
		buff := make([]byte,4096)
		for{
			//mytime := time.NewTimer(10*time.Second)
			n,err:=conn.Read(buff)//某个用户发来的消息
			msg := string(buff[:n])
			if n== 0{
				fmt.Printf("检测到用户%s退出,关闭连接",user.name)
				return
			} else if err!=nil{
				fmt.Println("con read err",err)
				return
			}else if "who\n" == msg||"who\r\n" == msg||"who" == msg{
				for _,user := range onlineMap{
					userinfo := user.addr+":"+user.name+"\n"
					conn.Write([]byte(userinfo))
				}
				goto lable
			}else if len(msg) >= 8 && msg[:6] == "rename"{
				//替换名称
				user.name = msg[8:]
				onlineMap[remoteAdder] = user
				conn.Write([]byte("rename success"))
				return
			}else if "exit" == msg{
				logoutIngfo := user.name+"logout"
				conn.Close()
				delete(onlineMap,user.addr)
				user.c1<- logoutIngfo
				//不应该这么做,应该通知所有人
				//需要监听
				Message<- logoutIngfo
				go printMessage(user,conn)
				Message<- string(buff[:n])
				goto lable
			}else {
				//将消息放入message中
				//go printMessage()
				go printMessage(user,conn)
				Message<- string(buff[:n])
			}
		}
		lable:
	}()
}

func logoutlisten(user User,conn net.Conn) {
	for{
		msg :=<-user.c1
		//需要将消息广播所有
		go func() {
			for _,v:= range onlineMap{
				v.c<-msg
			}
		}()
	}
}


func manager()  {
	onlineMap = make(map[string]User)
	for{
		msg:=<-Message
		//循环向其他user的chan写入shuju
		for _,v:= range onlineMap{
			v.c<-msg
		}
	}
}

//处理由客户端发来的数据


func connectWrite(user User,conn net.Conn)  {
	for msg:=range user.c{
		conn.Write([]byte(msg+"\n"))
	}
}

func main() {
	//需要tcp链接
	listen, err := net.Listen("tcp","127.0.0.1:8005")
	if err!=nil{
		fmt.Println("net listen err",err)
	}

	defer listen.Close()
	go manager()//创建管理者go程,管理map和全局chan
	//循环监听客户端链接请求
	for{
		conn,err2:= listen.Accept()
		if err2 !=nil{
			fmt.Println("listen accept err",err2)
			return
		}
		defer conn.Close()//某一个用户
		go handleConnect(conn)
		//群发消息
		go handleMessage(conn)
	}
}


func printMessage(user User,conn net.Conn) {
	for v:=range user.c{
		conn.Write([]byte(v))
	}
}

func handleMessage(conn net.Conn)  {
	for{
		//读消息,要知道读的来源是谁然后再发送至其他人,
		msg:=<-Message
		clientAddr:=conn.RemoteAddr().String()
		//这个用户发来了消息,将消息放到每个用户的chan中
		//监听接收
		//需要这个client对应的用户user
		//需要回归到用户

		for _,v:= range onlineMap{
			v.c<-"["+clientAddr+"]"+"发来数据"+":"+msg
		}
	}
}





A modified version

package main

import (
	"fmt"
	"net"
	_ "net/http"
)


//首先实现用户上线的功能,最后是用户修改自己的名字
var(
	//用chan进行读取
	//alladdr = make(chan net.Addr,100)
	onlineMap  map[string]User
	//Message = make(chan map[net.Addr]User)
	Message = make(chan string)//发送的消息是字符串

	logout = make(chan bool)
)


type User struct {
	addr string
	name string
	c chan string//用户登录
}

//还有两个功能,一个是修改自己的名称
//另一个是who之后返回所有

//最后是一个定时机制,就是超过10s没有连接通信的话就踢掉

//服务器处理客户端的通信事件//需要将用户存到map里面去
func handleConnect(conn net.Conn)  {
	remoteAdder := conn.RemoteAddr().String()
	user := User{remoteAdder,remoteAdder,make(chan string)}
	onlineMap[remoteAdder]=user//加入用户到map中,

	go connectWrite(user,conn)//这一个为什么可以触发全部的user,是每一个用户都会执行这一个协程

	//需要将上线消息广播至全网
	//用户上线,那么该用户的chan就写入数据,然后需要有全局的一个管理者一直在监听每个用户的chan
	//然后从每个用户的chan中监听读,读到有消息而且是login的话就打印出来
	Message<-"["+remoteAdder+"]"+"login"
	go func() {
		buff := make([]byte,4096)
		for{
			//mytime := time.NewTimer(10*time.Second)
			n,err:=conn.Read(buff)//某个用户发来的消息
			msg := string(buff[:n])
			if n== 0{
				logout<-true
				return
			} else if err!=nil{
				fmt.Println("con read err",err)
				return
			}else if "who\n" == msg||"who\r\n" == msg||"who" == msg{
				for _,user := range onlineMap{
					userinfo := user.addr+":"+user.name+"\n"
					conn.Write([]byte(userinfo))
				}
				goto lable
			}else if len(msg) >= 8 && msg[:6] == "rename"{
				//替换名称
				user.name = msg[8:]
				onlineMap[remoteAdder] = user
				conn.Write([]byte("rename success"))
				return
			}else if "exit" == msg{
				logout<-true
				conn.Close()
				goto lable
			}else {
				//将消息放入message中
				//go printMessage()
				go printMessage(user,conn)
				Message<- string(buff[:n])
			}
		}
		lable:
	}()

	for{
		select {
		case <-logout:
			conn.Close()
			delete(onlineMap,user.name)
			go printMessage(user,conn)
			Message<-user.name+"logout"
			return
		}
	}
}

func manager()  {
	onlineMap = make(map[string]User)
	for{
		msg:=<-Message
		//循环向其他user的chan写入shuju
		for _,v:= range onlineMap{
			v.c<-msg
		}
	}
}

//处理由客户端发来的数据


func connectWrite(user User,conn net.Conn)  {
	for msg:=range user.c{
		conn.Write([]byte(msg+"\n"))
	}
}

func main() {
	//需要tcp链接
	listen, err := net.Listen("tcp","127.0.0.1:8005")
	if err!=nil{
		fmt.Println("net listen err",err)
	}

	defer listen.Close()
	go manager()//创建管理者go程,管理map和全局chan
	//循环监听客户端链接请求
	for{
		conn,err2:= listen.Accept()
		if err2 !=nil{
			fmt.Println("listen accept err",err2)
			return
		}
		defer conn.Close()//某一个用户
		go handleConnect(conn)
		//群发消息
		go handleMessage(conn)
	}
}


func printMessage(user User,conn net.Conn) {
	for v:=range user.c{
		conn.Write([]byte(v))
	}
}

func handleMessage(conn net.Conn)  {
	for{
		//读消息,要知道读的来源是谁然后再发送至其他人,
		msg:=<-Message
		clientAddr:=conn.RemoteAddr().String()
		//这个用户发来了消息,将消息放到每个用户的chan中
		//监听接收
		//需要这个client对应的用户user
		//需要回归到用户

		for _,v:= range onlineMap{
			v.c<-"["+clientAddr+"]"+"发来数据"+":"+msg
		}
	}
}



Final Results

package main

import (
	"fmt"
	"net"
	_ "net/http"
	"time"
)


//首先实现用户上线的功能,最后是用户修改自己的名字
//还需要开发一个超时强制踢出
var(
	//用chan进行读取
	//alladdr = make(chan net.Addr,100)
	onlineMap  map[string]User
	//Message = make(chan map[net.Addr]User)
	Message = make(chan string)//发送的消息是字符串
	logout = make(chan bool)
	alive = make(chan bool)
)


type User struct {
	addr string
	name string
	c chan string//用户登录
}

//还有两个功能,一个是修改自己的名称
//另一个是who之后返回所有

//最后是一个定时机制,就是超过10s没有连接通信的话就踢掉

//服务器处理客户端的通信事件//需要将用户存到map里面去
func handleConnect(conn net.Conn)  {
	remoteAdder := conn.RemoteAddr().String()
	user := User{remoteAdder,remoteAdder,make(chan string)}
	onlineMap[remoteAdder]=user//加入用户到map中,

	go connectWrite(user,conn)//这一个为什么可以触发全部的user,是每一个用户都会执行这一个协程

	//需要将上线消息广播至全网
	//用户上线,那么该用户的chan就写入数据,然后需要有全局的一个管理者一直在监听每个用户的chan
	//然后从每个用户的chan中监听读,读到有消息而且是login的话就打印出来
	Message<-"["+remoteAdder+"]"+"login"
	go func() {
		buff := make([]byte,4096)
		for{
			n,err:=conn.Read(buff)//某个用户发来的消息
			msg := string(buff[:n])
			if n== 0{
				logout<-true
				return
			} else if err!=nil{
				fmt.Println("con read err",err)
				return
			}else if "who\n" == msg||"who\r\n" == msg||"who" == msg{
				for _,user := range onlineMap{
					userinfo := user.addr+":"+user.name+"\n"
					conn.Write([]byte(userinfo))
				}
				goto lable
			}else if len(msg) >= 8 && msg[:6] == "rename" {
				//替换名称
				user.name = msg[8:]
				onlineMap[remoteAdder] = user
				conn.Write([]byte("rename success"))
				return
			}else {
				//将消息放入message中
				//go printMessage()
				go printMessage(user,conn)
				Message<- string(buff[:n])
			}
			alive<-true
		}
		lable:
	}()

	for{
		select {
		case <-logout:
			conn.Close()
			delete(onlineMap,user.name)
			go printMessage(user,conn)
			Message<-user.name+"logout"
			return
		case <-alive:
			for{
				;
			}
		case <-time.After(60*time.Second):
			conn.Close()
			delete(onlineMap,user.name)
			go printMessage(user,conn)
			Message<-user.name+"time out"
			return
		}
	}
}

func manager()  {
	onlineMap = make(map[string]User)
	for{
		msg:=<-Message
		//循环向其他user的chan写入shuju
		for _,v:= range onlineMap{
			v.c<-msg
		}
	}
}

//处理由客户端发来的数据


func connectWrite(user User,conn net.Conn)  {
	for msg:=range user.c{
		conn.Write([]byte(msg+"\n"))
	}
}

func main() {
	//需要tcp链接
	listen, err := net.Listen("tcp","127.0.0.1:8005")
	if err!=nil{
		fmt.Println("net listen err",err)
	}

	defer listen.Close()
	go manager()//创建管理者go程,管理map和全局chan
	//循环监听客户端链接请求
	for{
		conn,err2:= listen.Accept()
		if err2 !=nil{
			fmt.Println("listen accept err",err2)
			return
		}
		defer conn.Close()//某一个用户
		go handleConnect(conn)
		//群发消息
		go handleMessage(conn)
	}
}


func printMessage(user User,conn net.Conn) {
	for v:=range user.c{
		conn.Write([]byte(v))
	}
}

func handleMessage(conn net.Conn)  {
	for{
		//读消息,要知道读的来源是谁然后再发送至其他人,
		msg:=<-Message
		clientAddr:=conn.RemoteAddr().String()
		//这个用户发来了消息,将消息放到每个用户的chan中
		//监听接收
		//需要这个client对应的用户user
		//需要回归到用户

		for _,v:= range onlineMap{
			v.c<-"["+clientAddr+"]"+"发来数据"+":"+msg
		}
	}
}





Published 74 original articles · won praise 2 · Views 6472

Guess you like

Origin blog.csdn.net/weixin_42067668/article/details/103516376