4. 在线用户查询
main.go | server.go | user.go
// server.go
type Server struct {IP stringPort int// 在线用户列表OnlineMap map[string]*UsermapLock sync.RWMutex// 消息广播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
}// 监听 Message 广播消息 channel 的 goroutine
func (this *Server) ListenMessager() {for {msg := <-this.Message// 将 msg 发送给所有在线Userthis.mapLock.Lock()for _, cli := range this.OnlineMap {cli.C <- msg}this.mapLock.Unlock()}
}// 广播消息方法
func (this *Server) BroadCast(user *User, msg string) {// "[user.Addr] user.Name: msg"sendMsg := "[" + user.Addr + "] " + user.Name + ": " + msgthis.Message <- sendMsg
}// 当前链接的业务
func (this *Server) Handler(conn net.Conn) {user := NewUser(conn, this)user.Online()// 接收客户端发送的消息go func() {buf := make([]byte, 4096)for {n, err := conn.Read(buf)// n = 0 表示对端关闭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)}}()}// 启动服务器接口
func (this *Server) Start() {// socket listenlistener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.IP, this.Port))if err != nil {fmt.Println("net.Listen err:", err)return}// close listen socketdefer listener.Close()// 启动监听 Message 的 goroutinego this.ListenMessager()for {// acceptconn, err := listener.Accept()if err != nil {fmt.Println("listener.Accept err:", err)continue}// do handlergo this.Handler(conn)}// close listen socket
}
// user.go
type User struct {Name stringAddr stringC chan stringconn net.Connserver *Server
}// 创建一个用户的API
func NewUser(conn net.Conn, server *Server) *User {userAddr := conn.RemoteAddr().String()user := &User{Name: userAddr,Addr: userAddr,C: make(chan string),conn: conn,server: server,}// 启动监听当前user channel消息的 goroutinego user.ListenMessage()return user
}// 监听当前User channel,一有消息就发送给对应客户端
func (this *User) ListenMessage() {for {msg := <-this.Cn, err := this.conn.Write([]byte(msg + "\n"))if n == 0 {fmt.Println("conn close")return}if err != nil {fmt.Println("conn Write error:", err)return}}
}// 用户上线业务
func (user *User) Online() {// 用户上线, 添加到OnlineMap中user.server.mapLock.Lock()user.server.OnlineMap[user.Name] = useruser.server.mapLock.Unlock()// 广播当前用户上线消息user.server.BroadCast(user, "online now")
}// 用户下线业务
func (user *User) Offline() {// 用户下线, 从OnlineMap中删除user.server.mapLock.Lock()delete(user.server.OnlineMap, user.Name)user.server.mapLock.Unlock()// 广播当前用户下线消息user.server.BroadCast(user, "offline now")
}// 发送消息
func (user *User) SendMsg(msg string) {user.conn.Write([]byte(msg))
}// 用户处理消息业务
func (user *User) DoMessage(msg string) {if msg == "who" {// 查询当前在线用户有哪些user.server.mapLock.Lock()for _, _user := range user.server.OnlineMap {onlineMsg := "[" + _user.Addr + "] " + _user.Name + ": " + "is online ...\n"user.SendMsg(onlineMsg)}user.server.mapLock.Unlock()} else {user.server.BroadCast(user, msg)}
}
5. 修改用户名
main.go | server.go | user.go
type User struct {Name stringAddr stringC chan stringconn net.Connserver *Server
}// 创建一个用户的API
func NewUser(conn net.Conn, server *Server) *User {userAddr := conn.RemoteAddr().String()user := &User{Name: userAddr,Addr: userAddr,C: make(chan string),conn: conn,server: server,}// 启动监听当前user channel消息的 goroutinego user.ListenMessage()return user
}// 监听当前User channel,一有消息就发送给对应客户端
func (this *User) ListenMessage() {for {msg := <-this.Cn, err := this.conn.Write([]byte(msg + "\n"))if n == 0 {fmt.Println("conn close")return}if err != nil {fmt.Println("conn Write error:", err)return}}
}// 用户上线业务
func (user *User) Online() {// 用户上线, 添加到OnlineMap中user.server.mapLock.Lock()user.server.OnlineMap[user.Name] = useruser.server.mapLock.Unlock()// 广播当前用户上线消息user.server.BroadCast(user, "online now")
}// 用户下线业务
func (user *User) Offline() {// 用户下线, 从OnlineMap中删除user.server.mapLock.Lock()delete(user.server.OnlineMap, user.Name)user.server.mapLock.Unlock()// 广播当前用户下线消息user.server.BroadCast(user, "offline now")
}// 发送消息
func (user *User) SendMsg(msg string) {user.conn.Write([]byte(msg))
}// 用户处理消息业务
func (user *User) DoMessage(msg string) {if msg == "who" {// 查询当前在线用户有哪些user.server.mapLock.Lock()for _, _user := range user.server.OnlineMap {onlineMsg := "[" + _user.Addr + "] " + _user.Name + ": " + "is online ...\n"user.SendMsg(onlineMsg)}user.server.mapLock.Unlock()} else if len(msg) > 7 && msg[:7] == "rename|" {// rename|newNamenewName := strings.Split(msg, "|")[1]// 判断 newName 是否存在_, ok := user.server.OnlineMap[newName]if ok {user.SendMsg("new name: " + newName + " is been used ...\n")} else {user.server.mapLock.Lock()delete(user.server.OnlineMap, user.Name)user.server.OnlineMap[newName] = useruser.server.mapLock.Unlock()user.Name = newNameuser.SendMsg("You has updated your name to \"" + user.Name + "\"\n")}} else {user.server.BroadCast(user, msg)}
}
6. 超时强踢
main.go | server.go | user.go
// server,go
type Server struct {IP stringPort int// 在线用户列表OnlineMap map[string]*UsermapLock sync.RWMutex// 消息广播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
}// 监听 Message 广播消息 channel 的 goroutine
func (this *Server) ListenMessager() {for {msg := <-this.Message// 将 msg 发送给所有在线Userthis.mapLock.Lock()for _, cli := range this.OnlineMap {cli.C <- msg}this.mapLock.Unlock()}
}// 广播消息方法
func (this *Server) BroadCast(user *User, msg string) {// "[user.Addr] user.Name: msg"sendMsg := "[" + user.Addr + "] " + user.Name + ": " + msgthis.Message <- sendMsg
}// 当前链接的业务
func (this *Server) Handler(conn net.Conn) {user := NewUser(conn, this)user.Online()// 监听用户是否活跃的 channelisAlive := make(chan bool)// 接收客户端发送的消息go func() {buf := make([]byte, 4096)for {n, err := conn.Read(buf)// n = 0 表示对端关闭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)// 用户的任意消息, 表示当前用户活跃isAlive <- true}}()// 当前 handler 阻塞for {select {case <-isAlive:// 当前用户活跃, 激活 select, 更新计时器case <-time.After(time.Second * 60):// 超时, 强制关闭当前 Useruser.SendMsg("You are out ...")// 销毁资源close(user.C)// 关闭连接conn.Close()// 退出当前 Handlerreturn // runtime.Goexit()}}
}// 启动服务器接口
func (this *Server) Start() {// socket listenlistener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.IP, this.Port))if err != nil {fmt.Println("net.Listen err:", err)return}// close listen socketdefer listener.Close()// 启动监听 Message 的 goroutinego this.ListenMessager()for {// acceptconn, err := listener.Accept()if err != nil {fmt.Println("listener.Accept err:", err)continue}// do handlergo this.Handler(conn)}// close listen socket
}
type User struct {Name stringAddr stringC chan stringconn net.Connserver *Server
}// 创建一个用户的API
func NewUser(conn net.Conn, server *Server) *User {userAddr := conn.RemoteAddr().String()user := &User{Name: userAddr,Addr: userAddr,C: make(chan string),conn: conn,server: server,}// 启动监听当前user channel消息的 goroutinego user.ListenMessage()return user
}// 监听当前User channel,一有消息就发送给对应客户端
func (this *User) ListenMessage() {for msg := range this.C {n, err := this.conn.Write([]byte(msg + "\n"))if n == 0 {fmt.Println("conn close")return}if err != nil {fmt.Println("conn Write error:", err)return}}
}// 用户上线业务
func (user *User) Online() {// 用户上线, 添加到OnlineMap中user.server.mapLock.Lock()user.server.OnlineMap[user.Name] = useruser.server.mapLock.Unlock()// 广播当前用户上线消息user.server.BroadCast(user, "online now")
}// 用户下线业务
func (user *User) Offline() {// 用户下线, 从OnlineMap中删除user.server.mapLock.Lock()delete(user.server.OnlineMap, user.Name)user.server.mapLock.Unlock()// 广播当前用户下线消息user.server.BroadCast(user, "offline now")
}// 发送消息
func (user *User) SendMsg(msg string) {user.conn.Write([]byte(msg))
}// 用户处理消息业务
func (user *User) DoMessage(msg string) {if msg == "who" {// 查询当前在线用户有哪些user.server.mapLock.Lock()for _, _user := range user.server.OnlineMap {onlineMsg := "[" + _user.Addr + "] " + _user.Name + ": " + "is online ...\n"user.SendMsg(onlineMsg)}user.server.mapLock.Unlock()} else if len(msg) > 7 && msg[:7] == "rename|" {// rename|newNamenewName := strings.Split(msg, "|")[1]// 判断 newName 是否存在_, ok := user.server.OnlineMap[newName]if ok {user.SendMsg("new name: " + newName + " is been used ...\n")} else {user.server.mapLock.Lock()delete(user.server.OnlineMap, user.Name)user.server.OnlineMap[newName] = useruser.server.mapLock.Unlock()user.Name = newNameuser.SendMsg("You has updated your name to \"" + user.Name + "\"\n")}} else {user.server.BroadCast(user, msg)}
}
7. 私聊功能
main.go | server.go | user.go
user.go
type User struct {Name stringAddr stringC chan stringconn net.Connserver *Server
}// 创建一个用户的API
func NewUser(conn net.Conn, server *Server) *User {userAddr := conn.RemoteAddr().String()user := &User{Name: userAddr,Addr: userAddr,C: make(chan string),conn: conn,server: server,}// 启动监听当前user channel消息的 goroutinego user.ListenMessage()return user
}// 监听当前User channel,一有消息就发送给对应客户端
func (this *User) ListenMessage() {for msg := range this.C {n, err := this.conn.Write([]byte(msg + "\n"))if n == 0 {fmt.Println("conn close")return}if err != nil {fmt.Println("conn Write error:", err)return}}
}// 用户上线业务
func (user *User) Online() {// 用户上线, 添加到OnlineMap中user.server.mapLock.Lock()user.server.OnlineMap[user.Name] = useruser.server.mapLock.Unlock()// 广播当前用户上线消息user.server.BroadCast(user, "online now")
}// 用户下线业务
func (user *User) Offline() {// 用户下线, 从OnlineMap中删除user.server.mapLock.Lock()delete(user.server.OnlineMap, user.Name)user.server.mapLock.Unlock()// 广播当前用户下线消息user.server.BroadCast(user, "offline now")
}// 发送消息
func (user *User) SendMsg(msg string) {user.conn.Write([]byte(msg))
}// 用户处理消息业务
func (user *User) DoMessage(msg string) {if msg == "who" {// 查询当前在线用户有哪些user.server.mapLock.Lock()for _, _user := range user.server.OnlineMap {onlineMsg := "[" + _user.Addr + "] " + _user.Name + ": " + "is online ...\n"user.SendMsg(onlineMsg)}user.server.mapLock.Unlock()} else if len(msg) > 7 && msg[:7] == "rename|" {// rename|newNamenewName := strings.Split(msg, "|")[1]// 判断 newName 是否存在_, ok := user.server.OnlineMap[newName]if ok {user.SendMsg("new name: " + newName + " is been used ...\n")} else {user.server.mapLock.Lock()delete(user.server.OnlineMap, user.Name)user.server.OnlineMap[newName] = useruser.server.mapLock.Unlock()user.Name = newNameuser.SendMsg("You has updated your name to \"" + user.Name + "\"\n")}} else if len(msg) > 4 && msg[:3] == "to|" {// to|name|message content// 1. 获取对方用户名remoteName := strings.Split(msg, "|")[1]if remoteName == "" {user.SendMsg("wrong msg format ... please use \"to|name|message content\"\n")return}// 2. 根据用户名得到对方 user 对象remoteUser, ok := user.server.OnlineMap[remoteName]if !ok {user.SendMsg("wrong username\n")return}// 3. 获取消息内容, 通过对方的 user 对象发送消息content := strings.Split(msg, "|")[2]if content == "" {user.SendMsg("mull message content ... please retry\n")return}remoteUser.SendMsg(user.Name + ": " + content + "\n")} else {user.server.BroadCast(user, msg)}
}