Go语言--广播式并发聊天服务器
实现功能
- 每个客户端上线,服务端可以向其他客户端广播上线信息;
- 发送的消息可以广播给其他在线的客户
- 支持改名
- 支持客户端主动退出
- 支持通过who查找当前在线的用户
- 超时退出
流程
变量
- 用户结构体 保存用户的管道,用户名以及网络地址信息
type Client struct {C chan string //用于发送数据的管道Name string //用户名Addr string //网络地址
}
- 保存在线用户的map表
var onlineMap map[string]Client
- 消息通道
var message = make(chan string)
主协程
- 监听客户端的连接请求
listener, err := net.Listen("tcp", "127.0.0.1:8000")
- 当客户端有消息发送,就向当前用户列表中所有在线用户转发消息
go Manager()
- 接受客户端的请求
conn, err1 := listener.Accept()
- 处理用户连接
go HandleConn(conn)
func main() {//监听listener, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen.err=", err)return}defer listener.Close()//新开一个协程,转发消息,只要有消息,就遍历map,给每个成员发送消息go Manager()//主协程,循环阻塞等待用户连接for {conn, err1 := listener.Accept()if err1 != nil {fmt.Println("listener.Accept.err1=", err1)continue}//处理用户连接go HandleConn(conn)}}
处理用户连接子协程
- 获取客户端的网络地址
cliAddr := conn.RemoteAddr().String()
- 创建一个用户结构体,默认:用户名和网络地址一样
cli := Client{make(chan string), cliAddr, cliAddr}
,加入map表 - 给客户端发送信息
go WriteMsgToClient(cli, conn)
- 广播某个人在线
message <- MakeMsg(cli, "login")
- 提示当前用户
cli.C <- MakeMsg(cli, "I am here")
- 判断用户状态isQuit hasData
- 接收用户的请求,查看当前用户who,改名rename,发送消息message
func HandleConn(conn net.Conn) {cliAddr := conn.RemoteAddr().String()cli := Client{make(chan string), cliAddr, cliAddr}//把结构体添加到maponlineMap[cliAddr] = cli//新开一个协程,给客户端发送信息go WriteMsgToClient(cli, conn)//广播某个人在线message <- MakeMsg(cli, "login")//提示当前用户cli.C <- MakeMsg(cli, "I am here")isQuit := make(chan bool) //对方是否主动退出hasData := make(chan bool) //对方是否有数据//新开一个协程,接收用户的请求go func() {buf := make([]byte, 2048)for {n, err := conn.Read(buf)if n == 0 {//对方断开或者出问题isQuit <- truefmt.Println("conn.Read.err=", err)return}msg := string(buf[:n-1])if len(msg) == 3 && msg == "who" {//遍历map,给当前用户发送所有成员conn.Write([]byte("user list:\n"))for _, tmp := range onlineMap {msg := tmp.Addr + ":" + tmp.Name + "\n"conn.Write([]byte(msg))}} else if len(msg) >= 8 && msg[:6] == "rename" {name := strings.Split(msg, "|")[1]cli.Name = nameonlineMap[cliAddr] = cliconn.Write([]byte("rename ok\n"))} else {message <- MakeMsg(cli, msg)}hasData <- true //代表有数据}}()for {//通过select检测channel的流动select {case <-isQuit:delete(onlineMap, cliAddr) //当前用户从map移除message <- MakeMsg(cli, "login out") //广播谁下线了returncase <-hasData:case <-time.After(60 * time.Second):delete(onlineMap, cliAddr)message <- MakeMsg(cli, "time out leave out")return}}}
给客户端发送信息
func WriteMsgToClient(cli Client, conn net.Conn) {for msg := range cli.C {conn.Write([]byte(msg + "\n"))}}
发送消息
func MakeMsg(cli Client, msg string) (buf string) {buf = "[" + cli.Addr + "]" + cli.Name + ":" + msgreturn
}
转发消息子协程
有消息到来就进行广播
- 给map分配空间
onlineMap = make(map[string]Client)
- 遍历在线用户列表,转发消息;没有消息之前message通道会阻塞
func Manager() {//给map分配空间onlineMap = make(map[string]Client)for {msg := <-message //没有消息前,会阻塞for _, cli := range onlineMap {cli.C <- msg}}
}
设计到的知识点
- 网络编程,监听客户端连接,处理连接请求,发送转发消息等
- map,切片,结构体数据,通道.
- 通过select检测channel的流动
- 并发编程,开辟子协程处理当前请求等
- 超时判断
效果展示
相关文章:

Go语言--广播式并发聊天服务器
实现功能 每个客户端上线,服务端可以向其他客户端广播上线信息;发送的消息可以广播给其他在线的客户支持改名支持客户端主动退出支持通过who查找当前在线的用户超时退出 流程 变量 用户结构体 保存用户的管道,用户名以及网络地址信息 typ…...

Spring MVC 全注解开发
1. Spring MVC 全注解开发 文章目录 1. Spring MVC 全注解开发2. web.xml 文件 的替代2.1 Servlet3.0新特性2.2 编写 WebAppInitializer 3. Spring MVC的配置3.1 Spring MVC的配置:开启注解驱动3.2 Spring MVC的配置:视图解析器3.3 Spring MVC的配置&…...

MQTT——Mosquitto使用(Linux订阅者+Win发布者)
前提:WSL(Ubuntu22)作为订阅者,本机Win10作为发布者。 1、Linux安装Mosquitto 命令行安装。 sudo apt-get install mosquitto 以上默认只安装了mosquitto的服务,不带测试客户端工具mosquitto_sub和mosquitto_pub。如…...

ArcGIS识别不GDB文件地理数据库显示为空?
点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 点击学习——>遥感影像综合处理4大遥感软件ArcGISENVIErdaseCognition 我们经常会碰到拷贝的GDB文件ArcGIS无法识别,软件只是把他当做普通的文件夹去看待&am…...

uniapp微信小程序 TypeError: $refs[ref].push is not a function
我的写法 this.$refs.addPopup.open();报错 打印出来是这样的 解决 参考未整理 原因 在当前页面使用的v-for循环 并且循环体内也有组件使用了ref(而我没有把每个ref做区别命名) 这样就导致了我有很多同名的ref,然后就报错了 解决办法&a…...

Django任务管理
1、用django-admin命令创建一个Django项目 django-admin startproject task_manager 2、进入到项目下用命令创建一个应用 cd task_manager python manage.py startapp tasks 3、进入models.py定义数学模型 第2步得到的只是应用的必要空文件,要开始增加各文件实际…...

Hive 常见问题
Hive 内部表和外部表的区别 外部表在创建时需要加关键字 external;创建内部表时,会将数据移动到数据仓库指定的路径;创建外部表时,不会移动数据,只会记录数据所在的路径;删除内部表时,会删除元…...

51单片机(STC8H8K64U/STC8051U34K64)_RA8889驱动大屏_硬件SPI4_参考代码(v1.3)
单片机实际不限,这里采用的STC最新、主推的型号,比如STC8H8K64U、STC8051U34K64进行实验测试,您可以换用不同型号。目前测试这两个系列,显示速度均相当不错,软件设计也是极为简单。各篇文章下方均提供源码供参考下载。…...

实习随笔【前端技术实现全局添加水印】
有一些数据比较重要的项目,往往需要对数据进行保护措施,本文介绍常见策略——全局添加水印。 1、创建水印组件 <template><div class"water-mark"><div class"water-mark-content"><span class"phone&qu…...

【软件测试】编写测试用例篇
前面部分主要是编写测试用例的方法和方向,后面一部分是编写出具体的测试用例 目录 什么是测试用例 1.设计测试用例的万能公式 1.1.从思维出发 1.2.万能公式 1.3.弱网测试 1.4.安装与卸载测试 2.设计测试用例的方法 2.1.基于需求的设计方法 2.2.等价类 2.3…...

转型AI产品经理需要掌握的硬知识(二):AI常见概念和算法梳理
上一篇文章介绍AI产品经理能力模型,人工智能的发展历史,人工智能常见概念的结构梳理,也简要做了BAT人工智能的优势分析,感兴趣的朋友可以点击链接查看上文。转型AI产品经理需要掌握的硬知识一:AI产品能力框架和看待AI的…...

mysql-connector-java 8.0.33 反序列化漏洞
前言 经过与oracle官方沟通,在最新的mysql-connector-j 9.0.0里不存在这个问题,所以他们不认为这是个漏洞 不过确实,mysql-connector-java这个分支已经迁移到mysql-connector-j了,当时没注意,交的时候只注意了mysql-c…...

基于Faster R-CNN的安全帽目标检测
基于Faster R-CNN的安全帽目标检测项目通常旨在解决工作场所,特别是建筑工地的安全监管问题。这类项目使用计算机视觉技术,特别是深度学习中的Faster R-CNN算法,来自动检测工人是否正确佩戴了安全帽,从而确保遵守安全规定并减少事…...

linux中vim切换输入中文
linux中vim切换输入中文 遇到问题 在虚拟机linux下vim 编辑器中注释的时候无法使用中文 解决方案 Linux系统中的vim编辑器中安装中文输入法软件包 1.在终端中输入以下命令 sudo apt-get install fcitx fcitx-bin fcitx-table-wubi fcitx-table-wbpy2. 安装完成后…...

嵌入式C++、Qt/QML和MQTT:智能工厂设备监控系统的全流程介绍(附代码示例)
1. 项目概述 本项目旨在开发一套先进的智能工厂设备监控系统,集成嵌入式技术、工业通信协议和人机界面等多项技术,实现对工厂设备的全方位实时监控、高精度数据采集和智能化分析。该系统将显著提升工厂设备的运行效率,大幅降低维护成本&…...

监控易V7.6.6.15升级详解8:机房动环管理功能
随着企业IT基础设施的不断发展,机房动环管理成为保障系统稳定运行的关键环节。为了满足广大用户对于机房动环管理的高效、精准需求,监控易系统近期完成了一次重要版本升级。本次升级不仅优化了原有功能,还新增了一系列实用特性,旨…...

C++ | Leetcode C++题解之第232题用栈实现队列
题目: 题解: class MyQueue { private:stack<int> inStack, outStack;void in2out() {while (!inStack.empty()) {outStack.push(inStack.top());inStack.pop();}}public:MyQueue() {}void push(int x) {inStack.push(x);}int pop() {if (outStac…...

Git-Updates were rejected 解决
Git-Updates were rejected 解决 文章目录 1. 杂话2. 问题3. 解决3.1 拉取远程的最新版本(AC)3.2 解决可能的冲突3.3 提交3.4 再次推送 1. 杂话 大伙儿应该都用过Git吧,具体是个啥东西我就不说了哈。之前我在用git push的时候遇到了这个报错&…...

Java常用的API_02(正则表达式、爬虫)
Java正则表达式 七、正则表达式7.1 格式7.1.1 字符类注意字符类示例代码1例2 7.1.2 预定义字符预定义字符示例代码例2 7.1.3 区别总结 7.2 使用Pattern和Matcher类与直接使用String类的matches方法的区别。(1) 使用Pattern和Matcher类示例代码 ÿ…...

2024最新图纸加密软件Top5排行榜
“小张,你听说了吗?最近我们部门又发生了一起图纸泄露事件,真是让人头疼。”小李眉头紧锁,手中紧握着一份重要的设计图纸。 “是啊,这图纸可是咱们的心血,一旦泄露出去,后果不堪设想。”小张回…...

每日一练 - IEEE 802.1Q中STP协议
01 真题题目 关于设备 SWC 的上述配置说法正确的是 (多选) A.SWC 为根交换机 B.stp instance 1 priority 4096 是配置交换机在实例 1 中的优先级为 4096, 该优先级默认为0 C.gtp edged-port enable 该命令是启用交换机 5WC 的 Ethernet 1/0/2 为边缘端口 D.sto …...

设计模式--工厂设计模式
什么是工厂模式? 工厂模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定要实例化的类是哪一个。这样,工厂方法模式让类的实例化延迟到子类。通过工厂方法模式,我们可以在不修改现有代码的情况下…...

消息队列-MQ
消息队列-MQ 1、什么是MQ?为什么要使用MQ?2、MQ有什么优缺点?3、有哪些常见的MQ实现?都有什么区别?4、MQ如何保证消息的可靠传输?消息丢了怎么办?5、如何保证消息的顺序性?6、如何解决消息队列的延时以及过期失效问题?7、消息队列满了以后该怎么处理?8、假设有几百万…...

近源渗透简介
什么是近源渗透 通过乔装、社工等方式实地物理侵入企业办公区域,通过其内部各种潜在攻击面(如Wi-Fi网络、RFID门禁、暴露的有线网口、USB接口等)获得“战果”,最后以隐秘的方式将评估结果带出上报,由此证明企业安全防…...

13 IP层协议-网际控制报文协议ICMP
计算机网络资料下载:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/140148186 为了更有效的转发IP数据报和提高交付成果的机会,在网际层使用了网际控制报文协议ICMP。ICMP允许主机或路由器报告差错情况和提供有关异常情况的报告。ICMP不是高层协议数…...

第一节Linux常见指令
目录 1.Linux下基本指令 ls指令 pwd 命令 cd 指令 知识点:理解树形结构 touch 指令 mkdir指令(重要) rmdir指令 && rm指令(重要) 知识点:ls file* 可以找到当前目录下任何以file开头的文件编辑 知识点:热键 man指令()重要 补充知识点:nano cp…...

嵌入式全栈设计思路:STM32G4+ChibiOS+FreeRTOS+PID控制+PFC算法构建高效智能电源管理系统(附代码示例)
智能电源管理系统是一个基于STM32G4微控制器的高性能数字电源控制解决方案。本项目旨在设计一个功能全面、高效稳定的电源管理系统,可广泛应用于工业控制、新能源、通信设备等领域。 1.1 系统主要特点 高精度数字电源控制:利用STM32G4的高性能ADC和定时器,实现精确…...

Linux驱动开发-04LED灯驱动实验(直接操作寄存器)
一、Linux 下LED 灯驱动原理 Linux 下的任何外设驱动,最终都是要配置相应的硬件寄存器。驱动访问底层的硬件除了使用内存映射将物理地址空间转化为虚拟地址空间,去进行读写修改,还可以通过各种子系统函数去进行操作 1.1 地址映射 MMU 全称…...

Linux命令更新-sort 和 uniq 命令
简介 sort 和 uniq 都是 Linux 系统中常用的文本处理命令。 sort 命令用于对文件内容进行排序。 uniq 命令用于去除文件中重复出现的行。 1. sort 命令 命令格式 sort [选项] [文件]选项: -n: 按照数字进行排序 -r: 反向排序 -c: 统计每个元素出现的次数 -…...
【密码学】密码学数学基础:剩余系
不得不啃的密码学数学基础之剩余系是个啥?数学里面有好多的定义都有前置的数学概念,要想弄懂剩余系还得先说说“同余”。 一、同余 那么“同余”有是个什么呢?在谈论“同余”之前,我们先圈定个讨论的范围。接下来讨论的都是整数集…...