package main import ( "fmt" "io" "net" "runtime" "sync" "time" ) type Server struct { Ip string Port int OnlineMap map[string]*User // 在线用户列表 mapLock sync.RWMutex // OnlineMap读写锁 Message chan string // 全部用户的消息管道 } // 创建一个server的接口 func NewServer(ip string, port int) *Server { server := &Server{ Ip: ip, Port: port, OnlineMap: make(map[string]*User), Message: make(chan string), } return server } // server类的成员方法:监听Message广播消息channel的goroutine, 一旦有消息就发送给全部的在线User func (server *Server) ListenMessage() { for { msg := <-server.Message // 将msg发送给全部的在线User server.mapLock.Lock() for _, cli := range server.OnlineMap { cli.C <- msg } server.mapLock.Unlock() } } // server类的成员方法:向所有在线客户端发送广播 func (server *Server) BroadCast(user *User, msg string) { sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg server.Message <- sendMsg } // server类的成员方法:处理客户端连接 func (server *Server) Handler(conn net.Conn) { user := NewUser(conn, server) // 当前连接的业务 fmt.Println(user.Name, "客户端连接建立成功") // 用户上线, 将用户加入到OnlineMap中 user.Online() // 监听用户是否活跃的channel isLive := make(chan bool) // 接收客户端发送的消息 go func() { buf := make([]byte, 4096) for { n, err := conn.Read(buf) if n == 0 { user.Offline() return } if err != nil && err != io.EOF { fmt.Println("Conn Read err:", err) return } // 提取用户的消息并去除"\n" msg := string(buf[:n-1]) // 将得到的消息进行广播 user.DoMessage(msg) // 用户的任意消息代表当前用户是一个活跃的,将true发给isLive管道 isLive <- true } }() // 设定定时器实现超时强踢 for { select { case <-isLive: // 当前用户是活跃的,应该重置定时器 // 不做任何事情,为了激活select,更新下面的定时器 // 只要执行time.After即实现重置定时器 case <-time.After(time.Second * 3600): // 已经超时,将当前User强制关闭 user.SendMsg("你被踢了") // 销毁用户的资源 close(user.C) // 关闭连接 conn.Close() // 退出 runtime.Goexit() // return } } } // Server类的成员方法:启动服务器的接口 func (server *Server) Start() { // socket listen listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", server.Ip, server.Port)) if err != nil { fmt.Println("net.Listen err: ", err) } // close listen socket defer listener.Close() // 启动监听Message的goroutine go server.ListenMessage() // 死循环实现监听 for { // accept conn, err := listener.Accept() if err != nil { fmt.Println("listener accept err:", err) continue } // do handler go server.Handler(conn) } }