当前位置: 首页 > news >正文

IMV8.0

一、背景内容

经历了多个版本,基础内容在前面,可以使用之前的基础环境:

v1:
https://blog.csdn.net/wtt234/article/details/132139454

v2:
https://blog.csdn.net/wtt234/article/details/132144907

v3:
https://blog.csdn.net/wtt234/article/details/132148572

v4:
https://blog.csdn.net/wtt234/article/details/132169338

v5:
https://blog.csdn.net/wtt234/article/details/132169651

v6:
https://blog.csdn.net/wtt234/article/details/132170959

v7:
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

http://www.lryc.cn/news/114505.html

相关文章:

  • 【Linux 网络】 数据链路层协议
  • GWJDN-400型2MHZ自动平衡高温介电温谱仪
  • 第十五次CCF计算机软件能力认证
  • ThreadPoolExecutor线程池详解
  • 【VB6|第22期】用SQL的方式读取Excel数据
  • 融云:从「对话框」跳进魔法世界,AIGC 带给社交的新范式
  • UWB伪应用场景 - 别再被商家忽悠
  • 【快应用】list组件属性的运用指导
  • js 面试题总结
  • HTML之表单标签
  • Java经典面试题总结(一)
  • Android监听设备亮灭屏广播(动态广播代码)
  • 【前端面试手撕题】简易深拷贝、深拷贝、寄生组合式继承、发布订阅模式、观察者模式
  • 【生物医学】应激(应激反应)全身适应综合征
  • 浅析基于安防监控EasyCVR视频汇聚融合技术的运输管理系统
  • VBA技术资料MF41:VBA_将常规数字转换为文本数字
  • Wavefront .OBJ文件格式解读【3D】
  • JavaScript:ES6中类与继承
  • 通用指令(汇编)
  • 苏宁数据治理实战方法论和三字经
  • 创建型设计模式:3、单例模式(C++实现实例 线程安全)
  • JavaWeb学习笔记
  • ad+硬件每日学习十个知识点(24)23.8.4(时序约束,SignalTap Ⅱ)
  • FortiGate防火墙日志审计运维
  • 基于yolo v5与Deep Sort进行车辆以及速度检测与目标跟踪实战
  • 以指标驱动,保险、零售、制造企业开启精益敏捷运营的新范式
  • MyBatis-动态SQL-foreach
  • VUE框架:vue2转vue3全面细节总结(3)路由组件传参
  • 音视频技术开发周刊 | 305
  • vue 图片base64转化