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

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

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

相关文章:

  • 地图坐标展示工具folium
  • Ruby 之方法委托
  • [论文笔记]RetroMAE
  • 服务熔断保护实践--Sentinal
  • 页面淘汰算法模拟实现与比较
  • FPGA实现HDMI转LVDS视频输出,纯verilog代码驱动,提供4套工程源码和技术支持
  • JAVA-easyexcel多sheet页导入
  • Java——比较器(一文搞懂比较器Comparable和Comparator)
  • 企业直播招聘抖音报白如何实现?怎么样才能报白成功?
  • 【考研数学】概率论与数理统计 —— 第七章 | 参数估计(2,参数估计量的评价、正态总体的区间估计)
  • 【设计模式】第10节:结构型模式之“组合模式”
  • 改进YOLOv3!IA-YOLO:恶劣天气下的目标检测
  • Vue路由跳转的几种方式
  • TiDB x 汉口银行丨分布式数据库应用实践
  • uci机器学习数据库简介
  • 多人协作使用git如何解决冲突?
  • 基于【逻辑回归】的评分卡模型金融借贷风控项目实战
  • 企业拉美跨境出海面对时延情况怎么办?
  • 【vector题解】只出现一次的数字 | 电话号码的数字组合
  • VS2022 开发方式
  • 【Python语言速回顾】——数据可视化基础
  • java实现pdf文件添加水印,下载到浏览器
  • 代码随想录算法训练营第四十一天丨 动态规划part04
  • PyCharm免费安装和新手使用教程
  • 使用Python的Scikit-Learn进行决策树建模和可视化:以隐形眼镜数据集为例
  • 开源软件:释放创新的力量,改变数字世界的游戏规则
  • 【QT】鼠标常用事件
  • LuatOS-SOC接口文档(air780E)--mlx90640 - 红外测温(MLX90640)
  • java连接本地数据库可以简写为///
  • 基于springboot漫画动漫网站