【Go自学版】03-即时通信系统2

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)}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/216195.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EMNLP2023 | 短篇论文接受列表,含全部论文下载

来源: AINLPer公众号&#xff08;每日干货分享&#xff01;&#xff01;&#xff09; 编辑: ShuYini 校稿: ShuYini 时间: 2023-12-12 引言 EMNLP2023 于12月10日在新加坡落下帷幕&#xff0c;此次会议顺利举行。今年EMNLP2023 的投稿论文数量将近5000篇&#xff0c;长论文接收…

人工智能|深度学习——知识蒸馏

一、引言 1.1 深度学习的优点 特征学习代替特征工程&#xff1a;深度学习通过从数据中自己学习出有效的特征表示&#xff0c;代替以往机器学习中繁琐的人工特征工程过程&#xff0c;举例来说&#xff0c;对于图片的猫狗识别问题&#xff0c;机器学习需要人工的设计、提取出猫的…

安装python

1.下载python 选择版本 选择可执行文件安装包 2.安装 输入python检查是否安装成功

(十六)Flask之蓝图

蓝图 Flask蓝图&#xff08;Blueprint&#xff09;是Flask框架中用于组织和管理路由、视图函数以及静态文件的一种机制。它提供了一种将应用程序拆分为更小、可重用组件的方式&#xff0c;使得项目结构更清晰&#xff0c;代码更易于维护。 使用Flask蓝图&#xff0c;可以将相…

​pickle --- Python 对象序列化​

源代码&#xff1a; Lib/pickle.py 模块 pickle 实现了对一个 Python 对象结构的二进制序列化和反序列化。 "pickling" 是将 Python 对象及其所拥有的层次结构转化为一个字节流的过程&#xff0c;而 "unpickling" 是相反的操作&#xff0c;会将&#xff08…

用Sketch for Mac轻松创作无限可能的矢量绘图

在如今的数码时代&#xff0c;矢量绘图软件成为了许多设计师和创意爱好者的必备工具。而在众多的矢量绘图软件中&#xff0c;Sketch for Mac无疑是最受欢迎的一款。它以其简洁易用的界面和强大的功能&#xff0c;让用户能够轻松创作出无限可能的矢量图形。 首先&#xff0c;Sk…

单域名https证书怎么申请

单域名https证书可以保护www和两个域名记录&#xff0c;如果保护的域名是子域名时&#xff0c;只能保护一个子域名。单域名https证书能够为网站提供加密的HTTPS连接&#xff0c;保护网站的数据安全。今天随SSL盾小编了解单域名https证书的申请。 1. 确定证书类型&#xff1a;根…

【Lidar】Laspy库介绍+基础函数(读取、可视化、保存、旋转、筛选、创建点云数据)

1 Laspy库介绍 laspy是一个Python库&#xff0c;主要用于读取、修改和创建LAS点云文件。该库兼容Python 2.6和3.5&#xff0c;并且可以处理LAS版本1.0-1.3的文件。 在laspy库中&#xff0c;可以使用命令行工具进行文件操作&#xff0c;如格式转换和验证&#xff0c;以及比较LAS…

Apache或Nginx在Linux上配置虚拟主机

在Linux上使用Apache或Nginx配置虚拟主机可以让您在同一台服务器上托管多个网站。这样不仅可以充分利用服务器资源&#xff0c;还能降低每个网站的运营成本。以下是使用Apache和Nginx配置虚拟主机的步骤。 使用Apache配置虚拟主机 安装Apache服务器软件。在终端中使用以下命令…

RK3568驱动指南|第八篇 设备树插件-第74章 虚拟文件系统ConfigFS介绍

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

mysql数据恢复

使用MySQL第三方工具binlog2sql binlog2sql&#xff0c;一款基于python开发的开源工具&#xff0c;是由大众点评团队的DBA使用python开发出来的&#xff0c;从MySQL binlog解析出你要的SQL。根据不同选项&#xff0c;你可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。其功…

大数据驱动下的人口普查:新时代下的新变革

人口普查数据大屏&#xff0c;是指一种通过大屏幕显示人口普查数据的设备&#xff0c;可以将人口普查数据以可视化的形式呈现出来&#xff0c;为决策者提供直观、准确的人口数据。这种大屏幕的出现&#xff0c;让人口普查数据的利用变得更加高效、便捷。 如果您需要制作一张直观…

一篇文章让你读懂Jenkins的用途

Jenkins是一款强大的自动化构建工具,广泛应用于软件开发和测试领域。它能够帮助团队在软件开发过程中实现自动化,从而提高生产效率和质量。下面我们将详细介绍Jenkins的用途。 1、持续集成与持续部署 Jenkins最大的特点是支持持续集成与持续部署。在软件开发过程中,持续集…

Linux目录创建的高级操作技巧和命令

在Linux系统中&#xff0c;创建目录是日常操作中的基础之一。除了常规的 mkdir 命令&#xff0c;还有一些高级的操作技巧和命令可以提高效率。本博客将介绍一些常用的目录创建方法&#xff0c;以及如何结合不同命令实现更复杂的目录结构。 1. 使用 mkdir 命令 基本创建&#x…

无人机高空巡查+智能视频监控技术,打造森林防火智慧方案

随着冬季的到来&#xff0c;森林防火的警钟再次敲响&#xff0c;由于森林面积广袤&#xff0c;地形复杂&#xff0c;且人员稀少&#xff0c;一旦发生火灾&#xff0c;人员无法及时发现&#xff0c;稍有疏忽就会酿成不可挽救的大祸。无人机高空巡查智能视频监控是一种非常有效的…

Linux:符号和符号表

文章目录 什么是符号&#xff1f;什么是符号表&#xff1f;全局符号和本地符号1. 全局符号&#xff1a;symtab符号表 2. 本地符号&#xff1a; 符号在汇编阶段符号在链接阶段1.由模块 m 定义并能被其他模块引用的全局符号。2.由其他模块定义并被模块 m 引用的全局符号。3.只被模…

Linux【2】:清理几天前的文件夹YYYYMMDD

Linux【2】&#xff1a;清理几天前的文件夹YYYYMMDD 1、清理指定日期【文件名】前文件夹脚本2、清理指定日期【文件日期】前的文件3、find命令说明 1、清理指定日期【文件名】前文件夹脚本 脚本如下#!/bin/bash #移除模糊目录下的日期文件夹 RemoveDir/root/tlogs/* dtdate %Y…

Ruoyi-vue上传下载文件

1. Controller /*** 修改文书发布记录*/RepeatSubmit //禁止重复提交Log(title "文书发布记录", businessType BusinessType.UPDATE)PostMapping("update") //RequestParam("xxx") RequestBody RequestPart("xxx") 这3个注解都…

深入了解ThreadLocal:避免内存泄漏的陷阱与最佳实践

多线程编程中&#xff0c;数据共享与隔离一直是开发者需要面对的挑战之一。而Java中的ThreadLocal提供了一种优雅的解决方案&#xff0c;允许每个线程都拥有自己独立的数据副本&#xff0c;从而避免了共享数据带来的线程安全问题。然而&#xff0c;正如事物总有两面性一样&…

Kimichat使用案例:将一大片无序文本内容整理成有序的Excel表格

Kimichat是一个国产的AI大模型应用。2024年10月9日&#xff0c;专注于通用人工智能领域的公司月之暗面&#xff08;Moonshot Al&#xff09;宣布在“长文本”领域实现了突破&#xff0c;推出了首个支持输入20万汉字的大模型moonshot&#xff0c;以及搭载该模型的智能助手产品Ki…