package main import ( "fmt" "net" "strings" "time" ) type Client struct { C chan string //用于发送数据的管道 Name string //用户名 Address string //IP地址 } //保存在线用户 var onLineMap map[string]Client var message = make(chan string) func Manager() { onLineMap = make(map[string]Client) for { msg := <-message //阻塞等待消息 for _, cli := range onLineMap { cli.C <- msg } } } //发送消息给客户端 func WriteMessageToClient(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.Address + "]" + cli.Name + ":" + msg return } //处理用户连接 func HandleConn(conn net.Conn) { defer conn.Close() //获取连接客户端网络地址 cliAddr := conn.RemoteAddr().String() //创建用户结构体 cli := Client{make(chan string), cliAddr, cliAddr} onLineMap[cliAddr] = cli //新建协程,发送消息给客户端 go WriteMessageToClient(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 <- true fmt.Println("conn.Read err=", err) return } msg := string(buf[:n-1]) if len(msg) == 3 && msg == "who" { //发送用户列表 conn.Write([]byte("user list:\n")) for _, data := range onLineMap { msg = data.Address + ":" + data.Name + "\n" conn.Write([]byte(msg)) } } else if len(msg) >= 8 && msg[:6] == "rename" { //修改用户名 cli.Name = strings.Split(msg, "|")[1] onLineMap[cli.Address] = cli conn.Write([]byte("rename success\n")) } else { //转发消息 message <- MakeMsg(cli, msg) } hasData <- true } }() for { select { case <-isQuit: delete(onLineMap, cli.Address) //用户退出登录,移除用户 message <- MakeMsg(cli, "login out") return case <-hasData: case <-time.After(60 * time.Second): //用户60秒不操作自动超时 delete(onLineMap, cli.Address) //用户退出登录,移除用户 message <- MakeMsg(cli, "time out leave out") return } } } func main() { //监听 listener, err := net.Listen("tcp", ":8000") if err != nil { fmt.Println("net.Listen err=", err) return } defer listener.Close() //新建一个协程,转发消息 go Manager() //主协程 for { conn, err := listener.Accept() if err != nil { fmt.Println("listener.Accept err=", err) continue } go HandleConn(conn) //处理用户连接 } }
原文地址:https://www.cnblogs.com/lemonzwt/p/10217190.html
时间: 2024-11-08 22:35:13