gorilla/websocket的chat示例代码简单分析

2023-11-03 11:45

本文主要是介绍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示例代码简单分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/337948

相关文章

Python多进程、多线程、协程典型示例解析(最新推荐)

《Python多进程、多线程、协程典型示例解析(最新推荐)》:本文主要介绍Python多进程、多线程、协程典型示例解析(最新推荐),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 目录一、multiprocessing(多进程)1. 模块简介2. 案例详解:并行计算平方和3. 实现逻

Vue中插槽slot的使用示例详解

《Vue中插槽slot的使用示例详解》:本文主要介绍Vue中插槽slot的使用示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、插槽是什么二、插槽分类2.1 匿名插槽2.2 具名插槽2.3 作用域插槽三、插槽的基本使用3.1 匿名插槽

uniapp小程序中实现无缝衔接滚动效果代码示例

《uniapp小程序中实现无缝衔接滚动效果代码示例》:本文主要介绍uniapp小程序中实现无缝衔接滚动效果的相关资料,该方法可以实现滚动内容中字的不同的颜色更改,并且可以根据需要进行艺术化更改和自... 组件滚动通知只能实现简单的滚动效果,不能实现滚动内容中的字进行不同颜色的更改,下面实现一个无缝衔接的滚动

C#通过进程调用外部应用的实现示例

《C#通过进程调用外部应用的实现示例》本文主要介绍了C#通过进程调用外部应用的实现示例,以WINFORM应用程序为例,在C#应用程序中调用PYTHON程序,具有一定的参考价值,感兴趣的可以了解一下... 目录窗口程序类进程信息类 系统设置类 以WINFORM应用程序为例,在C#应用程序中调用python程序

利用Python实现可回滚方案的示例代码

《利用Python实现可回滚方案的示例代码》很多项目翻车不是因为不会做,而是走错了方向却没法回头,技术选型失败的风险我们都清楚,但真正能提前规划“回滚方案”的人不多,本文从实际项目出发,教你如何用Py... 目录描述题解答案(核心思路)题解代码分析第一步:抽象缓存接口第二步:实现两个版本第三步:根据 Fea

Java计算经纬度距离的示例代码

《Java计算经纬度距离的示例代码》在Java中计算两个经纬度之间的距离,可以使用多种方法(代码示例均返回米为单位),文中整理了常用的5种方法,感兴趣的小伙伴可以了解一下... 目录1. Haversine公式(中等精度,推荐通用场景)2. 球面余弦定理(简单但精度较低)3. Vincenty公式(高精度,

QT6中绘制UI的两种方法详解与示例代码

《QT6中绘制UI的两种方法详解与示例代码》Qt6提供了两种主要的UI绘制技术:​​QML(QtMeta-ObjectLanguage)​​和​​C++Widgets​​,这两种技术各有优势,适用于不... 目录一、QML 技术详解1.1 QML 简介1.2 QML 的核心概念1.3 QML 示例:简单按钮

SQL Server中的PIVOT与UNPIVOT用法具体示例详解

《SQLServer中的PIVOT与UNPIVOT用法具体示例详解》这篇文章主要给大家介绍了关于SQLServer中的PIVOT与UNPIVOT用法的具体示例,SQLServer中PIVOT和U... 目录引言一、PIVOT:将行转换为列核心作用语法结构实战示例二、UNPIVOT:将列编程转换为行核心作用语

Python logging模块使用示例详解

《Pythonlogging模块使用示例详解》Python的logging模块是一个灵活且强大的日志记录工具,广泛应用于应用程序的调试、运行监控和问题排查,下面给大家介绍Pythonlogging模... 目录一、为什么使用 logging 模块?二、核心组件三、日志级别四、基本使用步骤五、快速配置(bas

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代