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

使用 Go 语言实现简单聊天系统

在互联网时代,聊天系统是常见的应用场景之一。无论是即时通讯、在线客服还是多人游戏中的消息系统,聊天功能的实现都是必不可少的。本文将使用 Go 语言,结合 WebSocket 来构建一个简单的多人聊天室系统。

一、项目结构

首先,我们设计一个简单的项目结构,文件结构如下:

go-chat/
│
├── main.go          // 主程序
├── client.go        // 处理客户端连接
└── hub.go           // 消息管理

WebSocket 简介

WebSocket 是一种基于 TCP 的网络协议,允许客户端和服务端建立持久的全双工通信连接。相比于传统的 HTTP 请求-响应模型,WebSocket 更加适合实时通信场景,因此它是实现聊天系统的理想选择。

二、实现思路

  1. 客户端连接管理:每个客户端通过 WebSocket 连接到服务器,服务器会为每个连接的客户端分配一个唯一的 connection
  2. 消息广播:当某个客户端发送消息时,服务器将该消息广播给所有连接的客户端。
  3. 并发处理:Go 原生支持并发编程,通过 Goroutine 和 Channel 可以轻松处理并发消息传递。

三、详细实现

1. main.go - 启动 WebSocket 服务

package mainimport ("log""net/http"
)func main() {hub := newHub()go hub.run()http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {serveWs(hub, w, r)})log.Println("服务器启动,监听端口 8080...")err := http.ListenAndServe(":8080", nil)if err != nil {log.Fatal("监听失败:", err)}
}

main.go 文件的作用是启动 HTTP 服务器,并在 /ws 路径上处理 WebSocket 连接请求。

2. hub.go - 消息管理中心

Hub 负责管理所有的客户端连接,以及消息的广播。

package main// Hub 负责管理所有客户端的注册、注销及消息广播
type Hub struct {clients    map[*Client]bool // 已连接的客户端broadcast  chan []byte      // 从客户端接收的广播消息register   chan *Client     // 注册请求unregister chan *Client     // 注销请求
}func newHub() *Hub {return &Hub{clients:    make(map[*Client]bool),broadcast:  make(chan []byte),register:   make(chan *Client),unregister: make(chan *Client),}
}func (h *Hub) run() {for {select {case client := <-h.register:h.clients[client] = truecase 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)}}}}
}
  • clients:保存当前连接的所有客户端。
  • broadcast:一个通道,用于广播消息给所有客户端。
  • register/unregister:用于客户端连接和断开的注册和注销。

3. client.go - 处理客户端连接

每个客户端的连接由 Client 结构体表示,并包含了 WebSocket 连接和发送消息的通道。

package mainimport ("github.com/gorilla/websocket""log""net/http""time"
)const (writeWait = 10 * time.SecondpongWait  = 60 * time.SecondpingPeriod = (pongWait * 9) / 10
)var upgrader = websocket.Upgrader{ReadBufferSize:  1024,WriteBufferSize: 1024,
}type Client struct {hub  *Hubconn *websocket.Connsend chan []byte
}func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) {conn, err := upgrader.Upgrade(w, r, nil)if err != nil {log.Println("升级到 WebSocket 失败:", err)return}client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)}client.hub.register <- clientgo client.writePump()go client.readPump()
}func (c *Client) readPump() {defer func() {c.hub.unregister <- cc.conn.Close()}()c.conn.SetReadLimit(512)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("读取错误: %v", err)}break}c.hub.broadcast <- message}
}func (c *Client) writePump() {ticker := time.NewTicker(pingPeriod)defer func() {ticker.Stop()c.conn.Close()}()for {select {case message, ok := <-c.send:c.conn.SetWriteDeadline(time.Now().Add(writeWait))if !ok {c.conn.WriteMessage(websocket.CloseMessage, []byte{})return}w, err := c.conn.NextWriter(websocket.TextMessage)if err != nil {return}w.Write(message)n := len(c.send)for i := 0; i < n; i++ {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:处理每个 WebSocket 连接请求,并为每个连接创建一个客户端实例。
  • readPump:从 WebSocket 连接中读取消息,并将消息广播到所有客户端。
  • writePump:负责将消息发送给客户端,并定期发送心跳检测(ping)消息以保持连接。

四、运行项目

  1. 首先,安装 WebSocket 依赖:

    go get github.com/gorilla/websocket
    
  2. 编写前端 HTML 页面(可用于测试),例如 index.html

    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Go 聊天室</title>
    </head>
    <body><div id="chatbox"></div><input id="msg" type="text" /><button onclick="sendMessage()">发送</button><script>var ws = new WebSocket("ws://localhost:8080/ws");ws.onmessage = function(event) {var chatbox = document.getElementById('chatbox');chatbox.innerHTML += event.data + "<br/>";};function sendMessage() {var msg = document.getElementById("msg").value;ws.send(msg);}</script>
    </body>
    </html>
    
  3. 运行 Go 服务:

    go run main.go
    
  4. 打开浏览器,访问 index.html,即可体验多人聊天室的功能。


http://www.mrgr.cn/news/30914.html

相关文章:

  • 3216. 交换后字典序最小的字符串
  • 半导体制造技术导论(第二版)萧宏 第二章集成电路工艺介绍答案
  • 容器技术在持续集成与持续交付中的应用
  • python printf中文乱码
  • Python用CEEMDAN-LSTM-VMD金融股价数据预测及SVR、AR、HAR对比可视化
  • 【已为网站上传证书,却显示不安全】
  • 【AI视频】Runway Gen-2:图文生视频与运动模式详解
  • 微信小程序. tarojs webView的 onload 事件不触发
  • 解决哈希冲突的方法
  • 1--SpringBoot外卖项目介绍及环境搭建 详解
  • 集采良药:从“天价神药”到低价良药,伊马替尼的真实世界研究!
  • 使用Python进行图像处理的11个基本操作
  • 常用函数式接口的使用
  • SpringBoot开发——整合SpringDoc实现在线接口文档
  • 一文搞懂软著申请细则!
  • 上海市计算机学会竞赛平台2024年7月月赛丙组子集归零
  • 数据库数据恢复—SQL Server附加数据库出现“错误823”怎么恢复数据?
  • 编程的魅力
  • 灵当CRM系统index.php存在SQL注入漏洞
  • 由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(六)
  • 计算机知识包括哪些和应用?
  • 如何通过全面技术方案与灵活商务服务引领实时云渲染的未来?
  • 滚雪球学SpringCloud[6.2讲]: Zipkin:分布式追踪系统详解
  • 30个小米集团芯片工程师岗位面试真题
  • VMware Fusion 虚拟机Mac版 安装CentOS8 系统教程
  • 教你在本地部署AI大模型,效果很赞!