IMV8.0
一、背景内容
经历了多个版本,基础内容在前面,可以使用之前的基础环境:
v1:
https://blog.csdn.net/wtt234/article/details/132139454v2:
https://blog.csdn.net/wtt234/article/details/132144907v3:
https://blog.csdn.net/wtt234/article/details/132148572v4:
https://blog.csdn.net/wtt234/article/details/132169338v5:
https://blog.csdn.net/wtt234/article/details/132169651v6:
https://blog.csdn.net/wtt234/article/details/132170959v7:
https://blog.csdn.net/wtt234/article/details/132171479

二、代码
2.1user.go
package mainimport ("net""strings"
)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
}//用户的上线业务
func (this *User) Online() {//用户上线,将用户加入到onlineMap中this.server.mapLock.Lock()this.server.OnlineMap[this.Name] = thisthis.server.mapLock.Unlock()//广播当前用户上线消息this.server.BroadCast(this, "已上线")
}//用户的下线业务
func (this *User) Offline() {//用户下线,将用户从onlineMap中删除this.server.mapLock.Lock()delete(this.server.OnlineMap, this.Name)this.server.mapLock.Unlock()//广播当前用户上线消息this.server.BroadCast(this, "下线")}//给当前User对应的客户端发送消息
func (this *User) SendMsg(msg string) {this.conn.Write([]byte(msg))
}//用户处理消息的业务
func (this *User) DoMessage(msg string) {if msg == "who" {//查询当前在线用户都有哪些this.server.mapLock.Lock()for _, user := range this.server.OnlineMap {onlineMsg := "[" + user.Addr + "]" + user.Name + ":" + "在线...\n"this.SendMsg(onlineMsg)}this.server.mapLock.Unlock()} else if len(msg) > 7 && msg[:7] == "rename|" {//消息格式: rename|张三newName := strings.Split(msg, "|")[1]//判断name是否存在_, ok := this.server.OnlineMap[newName]if ok {this.SendMsg("当前用户名被使用\n")} else {this.server.mapLock.Lock()delete(this.server.OnlineMap, this.Name)this.server.OnlineMap[newName] = thisthis.server.mapLock.Unlock()this.Name = newNamethis.SendMsg("您已经更新用户名:" + this.Name + "\n")}} else if len(msg) > 4 && msg[:3] == "to|" {//消息格式: to|张三|消息内容//1 获取对方的用户名remoteName := strings.Split(msg, "|")[1]if remoteName == "" {this.SendMsg("消息格式不正确,请使用 \"to|张三|你好啊\"格式。\n")return}//2 根据用户名 得到对方User对象remoteUser, ok := this.server.OnlineMap[remoteName]if !ok {this.SendMsg("该用户名不不存在\n")return}//3 获取消息内容,通过对方的User对象将消息内容发送过去content := strings.Split(msg, "|")[2]if content == "" {this.SendMsg("无消息内容,请重发\n")return}remoteUser.SendMsg(this.Name + "对您说:" + content)} else {this.server.BroadCast(this, msg)}
}//监听当前User channel的 方法,一旦有消息,就直接发送给对端客户端
func (this *User) ListenMessage() {for {msg := <-this.Cthis.conn.Write([]byte(msg + "\n"))}
}
2.2server.go
package mainimport ("fmt""io""net""sync""time"
)type Server struct {Ip stringPort int//在线用户的列表OnlineMap map[string]*UsermapLock sync.RWMutex//消息广播的channelMessage 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,一旦有消息就发送给全部的在线User
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) {sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msgthis.Message <- sendMsg
}func (this *Server) Handler(conn net.Conn) {//...当前链接的业务//fmt.Println("链接建立成功")user := NewUser(conn, this)user.Online()//监听用户是否活跃的channelisLive := 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])//用户针对msg进行消息处理user.DoMessage(msg)//用户的任意消息,代表当前用户是一个活跃的isLive <- true}}()//当前handler阻塞for {select {case <-isLive://当前用户是活跃的,应该重置定时器//不做任何事情,为了激活select,更新下面的定时器case <-time.After(time.Second * 300)://已经超时//将当前的User强制的关闭user.SendMsg("你被踢了")//销毁用的资源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)}
}
2.3main.go
package mainfunc main() {server := NewServer("127.0.0.1", 8888)server.Start()
}
三、客户端测试




至此服务端内容已经完成了,
具体内容大家可以看,写的非常好,同时建议学习他的其它的go的内容,作品质量比较高!
刘丹冰 golang内容
https://gitee.com/Aceld
https://github.com/aceld
相关文章:
IMV8.0
一、背景内容 经历了多个版本,基础内容在前面,可以使用之前的基础环境: v1: https://blog.csdn.net/wtt234/article/details/132139454 v2: https://blog.csdn.net/wtt234/article/details/132144907 v3: h…...
【Linux 网络】 数据链路层协议
数据链路层协议 数据链路层解决的问题以太网协议认识以太网以太网帧格式 认识MAC地址对比理解MAC地址和IP地址认识MTUMTU对IP协议的影响MTU对UDP协议的影响MTU对于TCP协议的影响ARP协议ARP协议的作用ARP协议的工作流程ARP数据报的格式 总结 数据链路层解决的问题 IP拥有将数据跨…...
GWJDN-400型2MHZ自动平衡高温介电温谱仪
GWJDN-400型2MHZ自动平衡高温介电温谱仪 GWJDN-400型2MHZ自动平衡高温介电温谱仪 关键词:介电常数,高温介电,自动平衡 主要功能: 材料介电常数测试仪 半导体材料的介电常数、导电率和C-V特性液晶材料:液晶单元的介电常数、弹性…...
第十五次CCF计算机软件能力认证
第一题:小明上学 小明是汉东省政法大学附属中学的一名学生,他每天都要骑自行车往返于家和学校。 为了能尽可能充足地睡眠,他希望能够预计自己上学所需要的时间。 他上学需要经过数段道路,相邻两段道路之间设有至多一盏红绿灯。 京…...
ThreadPoolExecutor线程池详解
ThreadPoolExecutor线程池详解 1. 背景 项目最近的迭代中使用到了ThreadPoolExecutor线程池,之前都只是知道怎么用,没有了解过线程池的底层原理,项目刚上线,有时间整理一下线程池的用法,学习一下线程池的底层实现与工…...
【VB6|第22期】用SQL的方式读取Excel数据
日期:2023年8月7日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方ÿ…...
融云:从「对话框」跳进魔法世界,AIGC 带给社交的新范式
8 月 17 日(周四),融云将带来直播课-《北极星如何协助开发者排查问题与预警风险?》欢迎点击上方报名~ AIGC 与社交结合的应用主要分两种,一是发乎于 AIGC,以大模型为基础提供虚拟伴侣等服务的 Appÿ…...
UWB伪应用场景 - 别再被商家忽悠
近几年UWB技术在网上宣传得如火如荼,与高精度定位几乎或等号,笔者认为这是营销界上的一大成功案例。 UWB超宽带技术凭借着低功耗、高精度,确实在物联网行业混得风生水起,但在无数实际应用案例中,根据客户的反馈情况&a…...
【快应用】list组件属性的运用指导
【关键词】 list、瀑布流、刷新、页面布局 【问题背景】 1、 页面部分内容需要瀑布流格式展示,在使用lsit列表组件设置columns进行多列渲染时,此时在里面加入刷新动画时,动画只占了list组件的一列,并没有完全占据一行宽度&…...
js 面试题总结
js 面试题总结 文章目录 js 面试题总结近百道面试题1、实现 子元素 在父元素中垂直居中的方式2、实现 子元素 在父元素中水平 垂直居中的方式3、描述 Keepealive 的作用,有哪些钩子函数,如何控制组件级存列表?4、请写出判断对象是数组的三个方法5、请说…...
HTML之表单标签
目录 表单标签 Form表单 定义: 基本语法结构: form属性: enctyoe属性 fieldeset标签 fieldeset属性 legend标签 label标签 优势 label属性 input标签 input属性 input标签中的type属性 text text输入框有以下配套属性 searc bu…...
Java经典面试题总结(一)
Java经典面试题总结(一) 题一:Java编译运行原理题二:JDK,JVM,JRE三者之间的关系题三:谈一下对冯诺依曼体系的了解题四:重载与重写的区别题五:拆箱装箱是指什么࿱…...
Android监听设备亮灭屏广播(动态广播代码)
MainActivity中 public class MainActivity extends Activity {private WakeAndLockReceiver wakeAndLockReceiver;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//注册亮屏和息…...
【前端面试手撕题】简易深拷贝、深拷贝、寄生组合式继承、发布订阅模式、观察者模式
FED16 简易深拷贝 描述 请补全JavaScript代码,要求实现对象参数的深拷贝并返回拷贝之后的新对象。 注意: 参数对象和参数对象的每个数据项的数据类型范围仅在数组、普通对象({})、基本数据类型中]无需考虑循环引用问题 <!DO…...
【生物医学】应激(应激反应)全身适应综合征
最近在探索疲劳、负荷、应激方面的底层发生机制,遂整理了一些相关内容,以脑图方式呈现。本文以生物医学向为主。 OK,开始基础介绍:应激 (stress)是指在收到外部或内部、心理社会刺激下的非特异性适应反应。 本文主要收集整理了相…...
浅析基于安防监控EasyCVR视频汇聚融合技术的运输管理系统
一、项目背景 近年来,随着物流行业迅速发展,物流运输费用高、运输过程不透明、货损货差率高、供应链协同能力差等问题不断涌现,严重影响了物流作业效率,市场对于运输管理数字化需求愈发迫切。当前运输行业存在的难题如下…...
VBA技术资料MF41:VBA_将常规数字转换为文本数字
【分享成果,随喜正能量】时有落花至,远随流水香。人生漫长,不攀缘,不强求,按照自己喜欢的方式生活,不必太过在意,顺其自然就好。路再长也有终点,夜再黑也有尽头。 我给VBA的定义&am…...
Wavefront .OBJ文件格式解读【3D】
OBJ(或 .OBJ)是一种几何定义文件格式,最初由 Wavefront Technologies 为其高级可视化器动画包开发。 该文件格式是开放的,已被其他 3D 图形应用程序供应商采用。 OBJ 文件格式是一种简单的数据格式,仅表示 3D 几何体&…...
JavaScript:ES6中类与继承
在JavaScript编程中,ES6引入了一种更现代、更清晰的方式来定义对象和实现继承,那就是通过类和继承机制。本文将以通俗易懂的方式解释ES6中类与继承的概念,帮助你更好地理解和应用这些特性。 1. 类的创建与使用 类是一种模板,用于…...
通用指令(汇编)
一、数据处理指令1)数学运算数据运算指令的格式数据搬移指令立即数伪指令加法指令带进位的加法指令减法指令带借位的减法指令逆向减法指令乘法指令数据运算指令的扩展 2)逻辑运算按位与指令按位或指令按位异或指令左移指令右移指令位清零指令 3ÿ…...
从数字臃肿到高效存储:开源视频图片压缩解决方案深度解析
从数字臃肿到高效存储:开源视频图片压缩解决方案深度解析 【免费下载链接】compressO Convert any video/image into a tiny size. 100% free & open-source. Available for Mac, Windows & Linux. 项目地址: https://gitcode.com/gh_mirrors/co/compress…...
3分钟解决Visual C++运行库问题:一站式安装修复工具完全指南
3分钟解决Visual C运行库问题:一站式安装修复工具完全指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾被"找不到msvcp140.dll"…...
零依赖STL转STEP工具:5分钟实现3D格式无缝转换的完整指南
零依赖STL转STEP工具:5分钟实现3D格式无缝转换的完整指南 【免费下载链接】stltostp Convert stl files to STEP brep files 项目地址: https://gitcode.com/gh_mirrors/st/stltostp 在数字化制造和工程设计的交叉领域,STL到STEP格式转换已成为连…...
FPGA并行FIR滤波器设计:50MHz实时信号处理与Verilog实现
1. 项目概述与设计目标在数字信号处理(DSP)的硬件实现领域,FIR(有限长单位冲激响应)滤波器因其绝对稳定性和易于实现线性相位的特性,成为工程师手中的一把“瑞士军刀”。无论是通信系统中的信道均衡、音频处…...
高性能JSXBIN解码器架构设计:3大核心技术优势深度解析
高性能JSXBIN解码器架构设计:3大核心技术优势深度解析 【免费下载链接】jsxer A fast and accurate JSXBIN decompiler. 项目地址: https://gitcode.com/gh_mirrors/js/jsxer Jsxer是一个快速且准确的JSXBIN反编译器,专门用于将Adobe ExtendScrip…...
VSCode调试STM32实战:解决Cortex-Debug插件配置JLink/OpenOCD时最常见的5个报错
VSCode调试STM32实战:破解Cortex-Debug插件五大经典报错 当你在深夜赶工STM32项目,按下F5期待调试器顺利启动时,终端却弹出鲜红的错误信息——这种挫败感每个嵌入式开发者都深有体会。本文不重复那些基础配置教程,而是直击VSCode…...
LM567锁相环芯片实测:手把手教你搭建10kHz音频信号检测电路(附面包板接线图)
LM567锁相环芯片实战:从零构建10kHz音频检测电路全流程解析 在电子设计领域,频率检测一直是个既基础又关键的课题。无论是红外遥控信号解码、超声波测距,还是电磁导航系统,精准的频率识别都是实现功能的前提。而LM567这款经典的锁…...
别再死记硬背了!用Python手把手带你画一棵哈夫曼树(附完整代码)
用Python动态构建哈夫曼树:从理论到可视化的完整实践指南 在计算机科学中,数据压缩是一个永恒的话题。想象一下,当你需要传输大量数据时,如何用最少的比特数表示最多的信息?这就是哈夫曼编码要解决的问题。传统的教科书…...
基于电容触控与伺服电机的互动雪人制作:嵌入式编程与物理计算实践
1. 项目概述与核心思路又到了可以折腾点有趣小玩意儿的季节。这次我想分享一个特别适合在室内营造节日气氛,又能把嵌入式编程和手工制作结合起来的项目:一个会跳舞的互动雪人。这个项目的核心很简单——你触摸雪人的帽子,它就会随着音乐扭动身…...
OdinSerializer扩展开发完全手册:创建自定义序列化组件
OdinSerializer扩展开发完全手册:创建自定义序列化组件 【免费下载链接】odin-serializer Fast, robust, powerful and extendible .NET serializer built for Unity 项目地址: https://gitcode.com/gh_mirrors/od/odin-serializer OdinSerializer是一款专为…...

