gorilla/websocket的chat示例代码简单分析
代码地址:https://github.com/gorilla/websocket/tree/main/examples/chat
文件包含:main.go、hub.go、client.go、home.html
main.go文件
func main() {flag.Parse()hub := newHub() // 实例化Hubgo hub.run() // 使用chan处理 增删Hub的连接 和 广播消息http.HandleFunc("/", serveHome) // 访问home.html页面// 处理websockethttp.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {serveWs(hub, w, r)})server := &http.Server{Addr: *addr,ReadHeaderTimeout: 3 * time.Second,}err := server.ListenAndServe()if err != nil {log.Fatal("ListenAndServe: ", err)}
}
hub.go文件
// 相当于连接池
type Hub struct {// Registered clients.clients map[*Client]bool // 存放所有websocket连接// Inbound messages from the clients.broadcast chan []byte // 广播消息// Register requests from the clients.register chan *Client // 添加websocket连接// Unregister requests from clients.unregister chan *Client // 删除websocket连接
}// 实例化Hub
func newHub() *Hub {return &Hub{broadcast: make(chan []byte),register: make(chan *Client),unregister: make(chan *Client),clients: make(map[*Client]bool),}
}// 使用chan处理 增删Hub的连接 和 广播消息
func (h *Hub) run() {for {select {case client := <-h.register:h.clients[client] = true // 添加连接case client := <-h.unregister:if _, ok := h.clients[client]; ok {delete(h.clients, client) // 删除连接close(client.send)}case message := <-h.broadcast:for client := range h.clients {select {case client.send <- message: // 广播消息default:close(client.send)delete(h.clients, client)}}}}
}
client.go文件
// 连接
type Client struct {hub *Hub // 引用Hub// The websocket connection.conn *websocket.Conn // websocket连接// Buffered channel of outbound messages.send chan []byte // 消息发送chan
}// readPump pumps messages from the websocket connection to the hub.
//
// The application runs readPump in a per-connection goroutine. The application
// ensures that there is at most one reader on a connection by executing all
// reads from this goroutine.
func (c *Client) readPump() { // 读数据defer func() {c.hub.unregister <- cc.conn.Close()}()c.conn.SetReadLimit(maxMessageSize)c.conn.SetReadDeadline(time.Now().Add(pongWait))c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })for {_, message, err := c.conn.ReadMessage() // 接收消息if err != nil {if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {log.Printf("error: %v", err)}break}message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))c.hub.broadcast <- message // 将消息发送到广播消息chan}
}// writePump pumps messages from the hub to the websocket connection.
//
// A goroutine running writePump is started for each connection. The
// application ensures that there is at most one writer to a connection by
// executing all writes from this goroutine.
func (c *Client) writePump() { // 写数据ticker := time.NewTicker(pingPeriod)defer func() {ticker.Stop()c.conn.Close()}()for {select {case message, ok := <-c.send: // 从连接的chan接收消息c.conn.SetWriteDeadline(time.Now().Add(writeWait))if !ok {// The hub closed the channel.c.conn.WriteMessage(websocket.CloseMessage, []byte{})return}w, err := c.conn.NextWriter(websocket.TextMessage)if err != nil {return}w.Write(message) // 发送消息// Add queued chat messages to the current websocket message.n := len(c.send)for i := 0; i < n; i++ {w.Write(newline)w.Write(<-c.send)}if err := w.Close(); err != nil {return}case <-ticker.C:c.conn.SetWriteDeadline(time.Now().Add(writeWait))if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {return}}}
}// serveWs handles websocket requests from the peer.
func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) {conn, err := upgrader.Upgrade(w, r, nil)if err != nil {log.Println(err)return}// 初始化Clientclient := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)}client.hub.register <- client// Allow collection of memory referenced by the caller by doing all work in// new goroutines.go client.writePump() // 写数据go client.readPump() // 读数据
}
其他chat参考:
https://github.com/android-coco/chat
https://github.com/GoLangFengShen/chat
https://www.golangblogs.com/read/im/date-2023.02.19.09.38.24
相关文章:
gorilla/websocket的chat示例代码简单分析
代码地址:https://github.com/gorilla/websocket/tree/main/examples/chat 文件包含:main.go、hub.go、client.go、home.html main.go文件 func main() {flag.Parse()hub : newHub() // 实例化Hubgo hub.run() // 使用chan处理 增删Hub的连接 和 广播消…...
地图坐标展示工具folium
参考:https://github.com/python-visualization/folium https://zhuanlan.zhihu.com/p/384078185?utm_id0 https://www.w3cschool.cn/article/37568875.html 其他还有baidu:echarts 安装: pip install folium代码(离线地图&a…...
Ruby 之方法委托
ruby 方法委托的优点在于,可以将多个不同实例(或类)的方法组织在一起,然后进行统一调用,方便各类方法的统一管理。比如下边示例中的 color 和 username,本来是不同类里边的方法,但最后都可以统一…...
[论文笔记]RetroMAE
引言 RetroMAE,中文题目为 通过掩码自编码器预训练面向检索的语言模型。 尽管现在已经在许多重要的自然语言处理任务上进行了预训练,但对于密集检索来说,仍然需要探索有效的预训练策略。 本篇工作,作者提出RetroMAE,一个新的基于掩码自编码器(Masked Auto-Encoder,MAE)…...
服务熔断保护实践--Sentinal
目录 概述 环境说明 步骤 Sentinel服务端 Sentinel客户端 依赖 在客户端配置sentinel参数 测试 保护规则设置 设置资源名 设置默认的熔断规则 RestTemplate的流控规则 Feign的流控规则 概述 微服务有很多互相调用的服务,构成一系列的调用链路…...
页面淘汰算法模拟实现与比较
1.实验目标 利用标准C 语言,编程设计与实现最佳淘汰算法、先进先出淘汰算法、最近最久未使用淘汰算法、简单 Clock 淘汰算法及改进型 Clock 淘汰算法,并随机发生页面访问序列开展有关算法的测试及性能比较。 2.算法描述 1. 最佳淘汰算法(Op…...
FPGA实现HDMI转LVDS视频输出,纯verilog代码驱动,提供4套工程源码和技术支持
目录 1、前言免责声明 2、目前我这里已有的图像处理方案3、本 LVDS 方案的特点4、详细设计方案设计原理框图视频源选择静态彩条IT6802解码芯片配置及采集ADV7611解码芯片配置及采集silicon9011解码芯片配置及采集纯verilog的HDMI 解码模块奇偶场分离并串转换LVDS驱动 5、vivado…...
JAVA-easyexcel多sheet页导入
今天给宝子带来一套多sheet页导入的模板,话不多说直接上代码 String localFilePath "file.xlsx";JSONObject jsonObject JSON.parseObject(file);String useFile jsonObject.getString("file");useFileuseFile.replace("\\\\",&qu…...
Java——比较器(一文搞懂比较器Comparable和Comparator)
基于Comparable的接口类基于Comparator的接口类 1、比较器的Comparable接口类 Comparable类的定义: public interface Comparable<T>{ public int compareTo(T o); }2、Comparable比较器的返回值: 此方法返回一个int类型的数据,但是此int的值…...
企业直播招聘抖音报白如何实现?怎么样才能报白成功?
现在每天几亿人都在使用抖音等短视频平台进行娱乐或者工作学习,也有很多商家和企业利用抖音等短视频平台进行盈利和企业宣传相关的服务,其中比较典型的就是通过抖音直播等功能为自身企业进行招聘。 但是通过抖音等短视频平台进行招聘时,很多…...
【考研数学】概率论与数理统计 —— 第七章 | 参数估计(2,参数估计量的评价、正态总体的区间估计)
文章目录 一、参数估计量的评价标准1.1 无偏性1.2 有效性1.3 一致性 二、一个正态总体参数的双侧区间估计2.1 对参数 μ \mu μ 的双侧区间估计 三、一个正态总体的单侧置信区间四、两个正态总体的双侧置信区间写在最后 一、参数估计量的评价标准 1.1 无偏性 设 X X X 为总…...
【设计模式】第10节:结构型模式之“组合模式”
一、简介 组合模式:将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现。使用组合模式的前提在于࿰…...
改进YOLOv3!IA-YOLO:恶劣天气下的目标检测
恶劣天气条件下从低质量图像中定位目标还是极具挑战性的任务。现有的方法要么难以平衡图像增强和目标检测任务,要么往往忽略有利于检测的潜在信息。本文提出了一种新的图像自适应YOLO (IA-YOLO)框架,可以对每张图像进行自适应增强,以提高检测…...
Vue路由跳转的几种方式
1.this. $router.push( ) 跳转到指定的URL,在history栈中添加一个记录,点击后退会返回上一个页面。 1. 不带参数// 字符串this.$router.push(/home)this.$router.push(/home/first)// 对象this.$router.push({path:/home})this.$router.push({ path: /…...
TiDB x 汉口银行丨分布式数据库应用实践
汉口银行是一家城市商业银行,近年来专注科技金融、民生金融等领域。在数据库国产化改造中,汉口银行引入了 TiDB 数据库,并将其应用在重要业务系统:头寸系统中,实现了一栈式的数据服务,同时满足了高并发、低…...
uci机器学习数据库简介
UCI(University of California, Irvine)机器学习数据库是经过精心整理的、用于研究和开发机器学习算法的数据集合。UCI机器学习数据库是一个公开的、广泛使用的数据集合,它由加州大学欧文分校的计算机科学系维护。该数据库中包含了许多数据集…...
多人协作使用git如何解决冲突?
什么情况会产生冲突 git merge XXX(合并分支时的冲突): 当你尝试将一个分支的更改合并到另一个分支时,如果两个分支都修改了相同的文件的相同部分,Git 将无法自动解决冲突,因此会发生冲突。你需要手动解决这些冲突,然后…...
基于【逻辑回归】的评分卡模型金融借贷风控项目实战
背景知识: 在银行借贷过程中,评分卡是一种以分数形式来衡量一个客户的信用风险大小的手段。今天我们来复现一个评分A卡的模型。完整的模型开发所需流程包括:获取数据,数据清洗和特征工程,模型开发,…...
企业拉美跨境出海面对时延情况怎么办?
随着全球化不断发展,中国企业也不断向海外拓展业务,开拓市场,增加收入来源,扩大自身品牌影响力。然而出海企业面临不同以往的困难和挑战,在其中不可避免面临的跨境网络时延问题,如何选择区域进行部署企业业…...
【vector题解】只出现一次的数字 | 电话号码的数字组合
只出现一次的数字 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。 你必须设计并…...
微软VibeVoice-TTS真实案例:用AI生成多人访谈节目音频
微软VibeVoice-TTS真实案例:用AI生成多人访谈节目音频 1. 从零开始认识VibeVoice-TTS 你是否曾经想过,用AI来制作一档完整的访谈节目?不是简单的单人口播,而是包含主持人、嘉宾互动、自然对话转折的专业级音频内容。微软开源的V…...
剧本杀教程生成指南2025,解析,轻松掌握创作技巧
剧本杀教程生成指南2025,解析,轻松掌握创作技巧剧本杀作为一种新兴的娱乐方式,近年来在全球范围内迅速流行。随着越来越多的人加入到剧本杀的创作和体验中,如何高效地创作出高质量的剧本成为了一个热门话题。本文将为你提供一份详…...
OpenClaw多模型对比:Qwen3-14b_int4_awq与开源小模型任务表现
OpenClaw多模型对比:Qwen3-14b_int4_awq与开源小模型任务表现 1. 测试背景与动机 最近在折腾OpenClaw自动化工作流时,发现一个关键问题:同样的任务脚本,换不同的大模型后端,执行效果差异巨大。为了找到最适合个人办公…...
【学习笔记】C++(2)
C++学习笔记 三、进阶 —— 类和对象 1、概述 2、基础 —— 公有、私有、保护、构造、析构 3、拷贝构造、临时对象不能绑定到非const引用问题 4、浅拷贝、深拷贝、移动拷贝 5、静态 6、内联和外联 7、链表 8、函数模板和类模板 9、友元 10、继承-派生(1) —— 基础 11、继承-…...
滨会生物冲刺港股:年亏1.2亿 乐普生物与扬子江药业是股东
雷递网 雷建平 4月5日武汉滨会生物科技股份有限公司(简称:“滨会生物”)日前更新招股书,准备在港交所上市。滨会生物总计募资超10亿元,其中,2021年2月完成募资6亿元,2022年7月完成募资2.4亿元&a…...
Burp Suite实战:如何用Base64编码爆破网站登录(附完整配置流程)
Burp Suite高级实战:Base64编码爆破攻击的深度解析与防御策略 在渗透测试领域,认证机制的安全性评估始终是核心环节。Base64编码作为一种常见的数据表示方式,常被误认为具有加密功能而用于认证传输。本文将深入剖析如何利用Burp Suite对采用B…...
瑞芯微Linux驱动工程师面试技术要点解析
1. 瑞芯微Linux驱动工程师面试全解析 作为一名在嵌入式Linux领域摸爬滚打多年的老司机,今天想和大家分享一份瑞芯微社招Linux驱动工程师的真实面经。不同于网上那些泛泛而谈的面试技巧,这份面经完全基于实际项目经验展开,可以说是"写什么…...
OpenClaw性能调优:Qwen3-14B镜像响应速度提升3倍实操
OpenClaw性能调优:Qwen3-14B镜像响应速度提升3倍实操 1. 为什么需要性能调优? 上周我在用OpenClaw自动处理100份PDF文档时,发现一个奇怪现象:同样的任务,晚上执行比白天快得多。经过排查才发现,白天我的本…...
针对波动计算复杂性的吸收边界条件(PML 用于一般波动方程)附Matlab代码
✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码及仿真咨询…...
ALOHA开源双臂机器人系统全攻略:从核心价值到深度实践
ALOHA开源双臂机器人系统全攻略:从核心价值到深度实践 【免费下载链接】aloha 项目地址: https://gitcode.com/gh_mirrors/al/aloha 一、探索ALOHA:重新定义低成本双手机器人开发 什么是ALOHA系统 ALOHA(A Low-cost Open-source Ha…...
