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 项目目录

chatroom/
├── main.go
├── index.html
└── styles.css

3.2 各文件功能

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

4. 代码实现

4.1 main.go - 服务器端实现

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

package mainimport ("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.Connsend chan []byte
}type Hub struct {clients   map[*Client]boolbroadcast chan []bytemutex     sync.Mutex
}var hub = Hub{clients:   make(map[*Client]bool),broadcast: make(chan []byte),
}func (h *Hub) run() {for {msg := <-h.broadcasth.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] = truehub.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 - 客户端实现

<!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 - 样式定义

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. 代码运行流程图

+-------------------+
|   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库:
go get -u github.com/gorilla/websocket
  1. 在项目目录下运行服务器:
go run main.go
  1. 在浏览器中访问 http://localhost:8080 来使用聊天室。

6.2 测试聊天室

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

7. 总结与扩展

7.1 项目总结

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

7.2 可能的扩展功能

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

8. 参考资料

  • Go Documentation
  • Gorilla WebSocket
  • WebSocket Protocol

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/59141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

thinkphp6 使用workerman扩展开发tcp应用

代码 <?phpnamespace app\shop\controller;use think\worker\Server;class Tcp extends Server {protected $socket tcp://127.0.0.1:12345;protected $option [name > "order_tcp",count > 1,pidFile > worker.pid, // daemonize > true,…

工业4.0时代下的人工智能新发展

摘要&#xff1a;随着德国工业4.0时代以及中国制造2025的提出&#xff0c;工业智能化的改革的时代正逐渐到来&#xff0c;然而我国整体工业水平仍然处于工业2.0水平。围绕工业4.0中智能工厂、智能生产、智能物流这三大主题&#xff0c;结合国内外研究现状&#xff0c;对人工智能…

一步一步从asp.net core mvc中访问asp.net core WebApi

"从asp.net core mvc中访问asp.net core WebApi"看到这个标题是不是觉得很绕口啊&#xff0c;但的确就是要讲一讲这样的访问。前面我们介绍了微信小程序访问asp.net core webapi(感兴趣的童鞋可以看看前面的博文有关WEBAPI的搭建)&#xff0c;这里我们重点不关心如何…

【Python】关于python中overload装饰器详解

Python不像C、Java等语言可以进行函数的重载。Python是不可以进行函数重载的。下面的例子&#xff0c;虽然我们定义了三个test函数&#xff0c;但是在局部命名空间下&#xff0c;只有一个test函数&#xff0c;就是最有一个&#xff0c;也就是说最后一个test覆盖了前两个test。 …

Qt 获取当前系统中连接的所有USB设备的信息 lsusb版

Qt 获取当前系统中连接的所有USB设备的信息 lsusb版 flyfish 环境 Ubuntu22.04 Qt 6.2.4 实现的功能 枚举USB设备&#xff1a;使用lsusb命令获取当前系统中连接的所有USB设备的信息。 解析设备信息&#xff1a;将lsusb命令的输出按行分割&#xff0c;并提取每行中的总线号、…

使用git进行多人协作开发项目流程

使用git进行多人协作开发项目流程 当然&#xff0c;以下是一个整合了分支管理、Pull Request流程以及日常Git操作的完整GitHub多人协作开发教程。这个教程将从仓库的创建和设置开始&#xff0c;一直到开发流程和最终的代码合并&#xff0c;形成一个完整的工作流程。 完整的Gi…

[面试]Mysql的锁机制

一、锁的基本概念 MySQL中的锁主要用于控制多个事务对数据库资源的并发访问&#xff0c;以确保数据的一致性和完整性。锁机制是数据库并发控制的核心&#xff0c;通过锁定数据库中的资源来防止并发操作引发的数据冲突。 二、锁的分类 MySQL的锁按照作用范围可以分为表级锁和行…

计算2000-2100年,阳历11月11日,与阴历10月1日重叠的年份

# 计算2000-2100年&#xff0c;阳历11月11日&#xff0c;与阴历10月1日重叠的年份from datetime import datetime from lunardate import LunarDatedef find_matching_years(start_year, end_year):matching_years []for year in range(start_year, end_year 1):solar_date …

JVM学习之路(5)垃圾回收

目录 Java垃圾回收 方法区回收 方法区的回收 堆内存回收 引用计数法和可达性分析算法 查看GC Root 五种对象引用 软引用 ​编辑 弱引用 虚引用和终结器引用 垃圾回收算法&#xff1a; 垃圾回收算法的历史和分类 垃圾回收算法的评价标准 标记清除算法 复制算法 标记整理算法 分代…

ubuntu 20.04 NVIDIA驱动、cuda、cuDNN安装

1. NVIDIA驱动 系统设置->软件和更新->附加驱动->选择NVIDIA驱动->应用更改。该界面会自动根据电脑上的GPU显示推荐的NVIDIA显卡驱动。 运行nvidia-smi: NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver. Make sure that the lat…

docker如何实时查看项目的日志

1. 使用docker logs命令 基本语法和原理&#xff1a;docker logs命令用于获取容器的日志输出。默认情况下&#xff0c;它会显示容器启动后到当前时间的所有日志内容。当你在容器内的应用程序将日志输出到标准输出&#xff08;stdout&#xff09;或标准错误输出&#xff08;std…

Ubuntu18.04+ROS环境+moveit UR5机械臂仿真

目录 仿真环境&#xff1a; 1.下载Universal Robots机器人功能包 2.运行 Gazebo中的仿真模型 3.运行moveit运动规划 4.运行rviz并进行轨迹规划 仿真环境&#xff1a; 本文使用版本&#xff1a;Ubuntu18.04 ros版本&#xff1a;ros-melodic-desktop-full&#xff0c;安装…

C++11新特性(二)

目录 一、C11的{} 1.初始化列表 2.initializer_list 二、可变参数模版 1.语法与原理 2.包扩展 3.empalce接口 三、新的类功能 四、lambda 1.语法 2.捕捉列表 3.原理 五、句装器 1.function 2.bind 一、C11的{} 1.初始化列表 C11以后想统⼀初始化⽅式&#xff0…

python获取iOS最近业务日志的两种方法

当iOS UI自动化用例执行失败的时候&#xff0c;需要获取当时的业务日志&#xff0c;供后续分析使用。 现在已经把iOS沙盒目录挂载到本地&#xff0c;剩下的事情就是从沙盒目录中捞取当前的日志&#xff0c;沙盒中的日志文件较大&#xff0c;整体导出来也可以&#xff0c;但是会…

Flutter 小技巧之 Shader 实现酷炫的粒子动画

在之前的《不一样的思路实现炫酷 3D 翻页折叠动画》我们其实介绍过&#xff1a;如何使用 Shader 去实现一个 3D 的翻页效果&#xff0c;具体就是使用 Flutter 在 3.7 开始提供 Fragment Shader API &#xff0c;因为每个像素都会过 Fragment Shader &#xff0c;所以我们可以通…

实现3D热力图

实现思路 首先是需要用canvas绘制一个2D的热力图&#xff0c;如果你还不会&#xff0c;请看json绘制热力图。使用Threejs中的canvas贴图&#xff0c;将贴图贴在PlaneGeometry平面上。使用着色器材质&#xff0c;更具json中的数据让平面模型 拔地而起。使用Threejs内置的TWEEN&…

风险数据集市整体架构及技术实现

引言 在当今大数据时代&#xff0c;风险数据集市作为金融机构的核心基础设施之一&#xff0c;扮演着至关重要的角色。它不仅为银行、保险等金融机构提供了全面、准确的风险数据支持&#xff0c;还帮助这些机构实现了风险管理的精细化和智能化。本文将深入探讨一种基于大数据La…

使用k8s RBAC和ValidatingAdmissionPolicy 配合来校验用户权限

我先讲一下业务场景&#xff1a; k8s集群内部有几个重要的命名空间&#xff08;比如&#xff1a; kube-system, kube-public 等&#xff09;&#xff0c;这些命名空间除了管理员有权限&#xff0c;其他用户不可以操作&#xff08;编辑&#xff0c;删除&#xff09;这几个命名空…

2. Sharding-JDBC广播表和绑定表操作

1. 广播表实战 ⼴播表概念 1. 指所有的分⽚数据源中都存在的表&#xff0c;表结构和表中的数据在每个数据库中均完全⼀致。 2. 适⽤于数据量不⼤且需要与海量数据的表进⾏关联查询的场景。 3. 例如&#xff1a;字典表、配置表。注意 1. 分库分表中间件&#xff0c;对应的数据…

【C++打怪之路Lv13】- “继承“篇

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…