15分钟学 Go 实战项目三 : 实时聊天室(学习WebSocket并发处理)

实时聊天室:学习WebSocket并发处理

目标概述

在本项目中,我们将创建一个实时聊天室,使用Go语言和WebSocket来处理并发消息交流。这将帮助你深入理解WebSocket协议的工作原理以及如何在Go中实现并发处理。

1. 项目需求

功能需求

  • 用户可以通过浏览器连接到聊天室。
  • 用户能发送和接收消息。
  • 支持多个用户同时在线聊天。
  • 提供简单的用户界面,展示消息。

技术需求

  • Go语言: 用于后端服务器开发。
  • Gorilla WebSocket: Go语言实现的WebSocket库。
  • HTML/CSS/JavaScript: 用于前端界面开发。

2. 学习WebSocket

2.1 WebSocket概述

WebSocket是一种协议,允许在客户端和服务器之间建立持久性的全双工通信通道。它非常适合实时应用,如聊天应用、实时通知等。

WebSocket的优点
  • 全双工通信:客户端和服务器可以随时互相发送数据。
  • 低延迟:与HTTP相比,WebSocket在数据传输时会有更低的延迟。
  • 节省资源:WebSocket连接在建立后可以保持打开状态,避免重复连接。

2.2 WebSocket协议工作流

WebSocket的建立过程如下:

  1. 客户端发送HTTP请求升级连接至WebSocket。
  2. 服务器确认并完成连接协议升级。
  3. 完成后,双方可以开始进行实时数据传输。

3. 项目结构

3.1 项目目录

plaintext 复制代码
chatroom/
├── main.go
├── index.html
└── styles.css

3.2 各文件功能

  • main.go: 服务器的主逻辑。
  • index.html: 客户端聊天界面。
  • styles.css: 界面的样式定义。

4. 代码实现

4.1 main.go - 服务器端实现

下面是主要的Go代码实现,包含WebSocket处理和并发支持:

go 复制代码
package main

import (
	"fmt"
	"net/http"
	"sync"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

type Client struct {
	conn *websocket.Conn
	send chan []byte
}

type Hub struct {
	clients   map[*Client]bool
	broadcast chan []byte
	mutex     sync.Mutex
}

var hub = Hub{
	clients:   make(map[*Client]bool),
	broadcast: make(chan []byte),
}

func (h *Hub) run() {
	for {
		msg := <-h.broadcast
		h.mutex.Lock()
		for client := range h.clients {
			select {
			case client.send <- msg:
			default:
				close(client.send)
				delete(h.clients, client)
			}
		}
		h.mutex.Unlock()
	}
}

func (c *Client) read() {
	defer func() {
		hub.mutex.Lock()
		delete(hub.clients, c)
		hub.mutex.Unlock()
		c.conn.Close()
	}()
	for {
		_, msg, err := c.conn.ReadMessage()
		if err != nil {
			break
		}
		hub.broadcast <- msg
	}
}

func (c *Client) write() {
	defer c.conn.Close()
	for msg := range c.send {
		if err := c.conn.WriteMessage(websocket.TextMessage, msg); err != nil {
			break
		}
	}
}

func handleConnection(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	client := &Client{conn: conn, send: make(chan []byte)}
	hub.mutex.Lock()
	hub.clients[client] = true
	hub.mutex.Unlock()

	go client.write()
	client.read()
}

func main() {
	go hub.run()
	http.HandleFunc("/ws", handleConnection)
	http.Handle("/", http.FileServer(http.Dir("./")))
	fmt.Println("Server started at :8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Println("Error while starting the server:", err)
	}
}

4.2 index.html - 客户端实现

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chat Room</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="chat-container">
        <div id="messages"></div>
        <input id="message-input" type="text" placeholder="Type a message..." autocomplete="off" />
        <button id="send-button">Send</button>
    </div>
    <script>
        const messages = document.getElementById('messages');
        const input = document.getElementById('message-input');
        const sendButton = document.getElementById('send-button');

        const connection = new WebSocket('ws://' + window.location.host + '/ws');

        connection.onmessage = function(event) {
            const messageElement = document.createElement('div');
            messageElement.textContent = event.data;
            messages.appendChild(messageElement);
        };

        sendButton.onclick = function() {
            const message = input.value;
            if (message) {
                connection.send(message);
                input.value = '';
            }
        };
    </script>
</body>
</html>

4.3 styles.css - 样式定义

css 复制代码
body {
    font-family: Arial, sans-serif;
}

#chat-container {
    width: 600px;
    margin: 0 auto;
    border: 1px solid #ccc;
    padding: 10px;
}

#messages {
    height: 400px;
    overflow-y: scroll;
    border: 1px solid #ccc;
    margin-bottom: 10px;
}

#message-input {
    width: 80%;
    padding: 10px;
}

#send-button {
    padding: 10px;
}

5. 代码运行流程图

plaintext 复制代码
+-------------------+
|   Start Server    |
|   (main.go)      |
+---------+---------+
          |
          v
+-------------------+
|   Handle          |
|   WebSocket       |<--------------------+
|   Connection      |                     |
+---------+---------+                     |
          |                               |
          v                               |
+---------+---------+                     |
|   Create Client   |                     |
+---------+---------+                     |
          |                               |
          v                               |
+---------+---------+                     |
|   Read Message    |                     |
+---------+---------+                     |
          |                               |
          +--------------------->---------+
                               |
                               v
                    +----------+-----------+
                    |  Broadcast Message   |
                    +----------+-----------+
                               |
                               v
                    +----------+-----------+
                    |  Send Message to All |
                    +----------------------+

6. 运行项目

6.1 运行步骤

  1. 确保Go环境已经安装,并且你的工作目录在chatroom
  2. 安装Gorilla WebSocket库:
bash 复制代码
go get -u github.com/gorilla/websocket
  1. 在项目目录下运行服务器:
bash 复制代码
go run main.go
  1. 在浏览器中访问 http://localhost:8080 来使用聊天室。

6.2 测试聊天室

你可以在多个浏览器窗口中打开同一地址,发送消息以查看所有连接的用户是否可以实时收到消息。这将帮助你理解并发处理和WebSocket的使用。

7. 总结与扩展

7.1 项目总结

通过这个项目,你学习了如何使用Go语言创建一个支持WebSocket的实时聊天室。了解了WebSocket的工作原理,并掌握了Go中的并发处理方法,为以后的项目开发打下了基础。

7.2 可能的扩展功能

  • 用户身份验证:支持用户注册和登录功能。
  • 消息历史记录:将聊天记录存储到数据库。
  • 聊天室管理:允许用户创建和管理多个聊天室。
  • 客户端样式优化:提升用户界面的美观度和用户体验。

8. 参考资料


怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

相关推荐
知识分享小能手2 小时前
高等数学学习教程,从入门到精通,定积分 — 知识点全面总结(10)
学习·机器学习·概率论
只是甲7 小时前
Text2SQL 系列博客 02:技术原理深度剖析 - 从自然语言到 SQL 的完整链路
人工智能·text2sql·nl2sql·ai agent·自助数据分析·data agent·agentic 数据洞察
懷淰メ7 小时前
【AI赋能】基于PyQt+YOLO+DeepSeek水上漂浮物检测系统(详细介绍)
人工智能·yolo·目标检测·计算机视觉·pyqt·漂浮物·水上漂浮物
EQUINOX17 小时前
【论文精读】| CLIP精读
大数据·人工智能
PC2005-cloud8 小时前
博文已索引但不展示:一次 Bing SEO 问题排查记录
服务器·人工智能
weixin_408099678 小时前
2026 图片去文字 API 实战:AI一键去除图片文字(附 Python / Java / PHP / JS 完整代码)
人工智能·api接口·图片去水印·石榴智能·ai图像修复·图片去文字
greenbbLV8 小时前
2026节日慰问品政策解读:合规标准升级与福利行业新趋势
人工智能·节日
前端工作日常8 小时前
我学习到的Java 的 Service 分层:itf 和 impl 到底是什么?
java·后端
奈斯先生Vector8 小时前
告别工具碎片化:基于 Nano Banana 全模态 AI 聚合架构搭建“文本-图像-视频”自动化协同生产线
运维·数据库·人工智能·架构·自动化·aigc·音视频
领麦微红外8 小时前
国产MEMS红外测温传感器:传感器+算法+产品级出厂标定一站式交付模式深度解读
人工智能·硬件工程·产品经理