实时聊天应用程序是一种在线通信渠道,允许您进行实时对话。越来越多的开发人员利用 Redis 的强大功能,因为它速度极快,并且由于它支持各种丰富的数据结构,例如列表、集合、有序集合、哈希等。Redis 带有发布/订阅消息功能,允许开发人员通过生成多个服务器实例来扩展后端。
虽然 Redis 上传统的聊天应用程序教程仍然很有见地,但我们鼓励您深入了解我们的 AI 聊天机器人教程,以释放现代对话体验的潜力。
请注意,此代码是开源的。您可以在本教程末尾找到链接。
在本教程中,我们将了解如何使用 Flask、Socket.IO 和 Redis 开发实时消息应用程序。此示例使用 Redis 发布/订阅功能与 WebSockets 结合使用,以实现客户端和服务器之间实时聊天应用程序通信。
请注意,此代码是开源的,并实现了实时聊天应用程序的基本功能。您可以在本教程末尾找到链接。
为了执行此即时消息应用程序开发,您需要以下软件
首先,我们将克隆实现基本聊天功能的项目。
git clone https://github.com/redis-developer/basic-redis-chat-app-demo-python
cd client
yarn install
要运行聊天应用程序的前端,请运行以下命令
yarn start
You can now access a chat window in the browser.
Local: https://localhost:3000
On Your Network: https://192.168.1.9:3000
cd ..
pip3 install -r requirements.txt
要启动完整的聊天应用程序,请运行以下命令
python3 -m venv venv/
source venv/bin/activate
python3 app.py
python3 app.py
* Restarting with stat
* Debugger is active!
* Debugger PIN: 220-696-610
(8122) wsgi starting up on https://127.0.0.1:5000
此即时消息应用程序服务器充当基本的 REST API,它涉及在聊天室中维护会话和处理用户状态(除了 WebSocket/实时部分)。当服务器启动时,会发生初始化步骤。首先,建立一个新的 Redis 连接,并检查是否需要加载演示数据。
为简单起见,检查一个名为 total_users 的键的值:如果该键不存在,我们将在 Redis 数据库中填充初始数据。EXISTS total_users(检查键是否存在)演示数据初始化分多个步骤进行。
我们创建一个新的用户 ID:INCR total_users。然后我们根据用户名设置用户 ID 查找键:例如
SET username:nick user:1
最后,将剩余数据写入哈希集
示例
HSET user:1 username "nick" password "bcrypt_hashed_password".
此外,每个用户都会被添加到默认的“通用”房间中。为了处理每个用户的聊天室,我们有一个集合来保存聊天室 ID。以下是如何添加房间的示例命令
SADD user:1:rooms "0"
填充用户之间的私人消息。首先,创建私人房间:如果需要建立私人房间,则会为每个用户生成一个房间 ID:room:1:2,其中数字对应于用户 ID,按升序排列。
例如,在 2 个用户之间创建一个私人房间
SADD user:1:rooms 1:2 and SADD user:2:rooms 1:2
然后,我们通过写入排序集合来向此房间添加消息
ZADD room:1:2 1615480369 "{'from': 1, 'date': 1615480369, 'message': 'Hello', 'roomId': '1:2'}"
我们使用字符串化的 JSON 来保持消息结构,并简化此演示应用程序的实现细节。
用消息填充“通用”房间。消息被添加到排序集合中,该排序集合的 ID 为“通用”房间:room:0
初始化后,将创建发布/订阅订阅:SUBSCRIBE MESSAGES。同时,每个服务器实例都会在该频道上的消息上运行一个监听器,以接收实时更新。
同样,为简单起见,每条消息都被序列化为 JSON,然后我们将解析它们,并以与 WebSocket 消息相同的方式进行处理。
发布/订阅允许连接多个用不同平台编写的服务器,而无需考虑每个服务器的实现细节。
当实例化一个 WebSocket/实时服务器时,它会监听接下来的事件
一个名为 online_users 的全局集合用于保存每个用户的在线状态。因此,在新的连接上,用户 ID 会被写入该集合
SADD online_users 1
这里我们将 ID 为 1 的用户添加到 online_users 集合中
之后,会向客户端广播一条消息,通知他们有一个新用户加入了聊天。
PUBLISH message "{'serverId': 4132, 'type':'message', 'data': {'from': 1, 'date': 1615480369, 'message': 'Hello', 'roomId': '1:2'}}"
请注意,我们发送了与消息类型和服务器 ID 相关的附加数据。服务器 ID 用于丢弃发送它们的服务器实例的消息,因为它连接到相同的 MESSAGES 频道。
序列化 JSON 的 type 字段对应于我们用于实时通信的实时方法(连接/断开连接/消息)。
data 字段是方法特定的信息。在上面的示例中,它与新消息相关。
Redis 主要用作数据库,用于保存用户/消息数据以及在连接的服务器之间发送消息。
实时功能由 Socket.IO 处理,用于服务器-客户端消息传递。此外,每个服务器实例都会订阅发布/订阅的 MESSAGES 频道,并在消息到达时调度消息。请注意,服务器使用单独的事件流(由服务器发送的事件处理)传输发布/订阅消息,这是由于需要在 socket.io 信号之外运行发布/订阅消息循环。
聊天数据存储在不同的键和不同的数据类型中。用户数据存储在哈希集中,每个用户条目包含以下值
用户名:唯一的用户名;
密码:哈希密码
此外,一组聊天室与用户相关联
房间是排序集合,其中包含消息,每个消息的得分是该消息的时间戳
每个聊天室都有一个与之关联的名称
“在线”集合对所有用户都是全局的,用于跟踪哪些用户在线。
每个用户哈希集通过键 user:{userId} 访问。其数据使用 HSET key field data
存储。用户 ID 通过递增 total_users
键计算 (INCR total_users
)
用户名存储为单独的键 (username:{username}
),返回 userId 以便快速访问,并使用 SET username:{username} {userId}
存储。
用户所属的房间存储在 user:{userId}:rooms
中,作为聊天室 ID 集合。通过 SADD user:{userId}:rooms {roomId}
命令添加房间。
消息存储在 room:{roomId}
键中,使用有序集合(如上所述)。它们使用 ZADD room:{roomId} {timestamp} {message}
命令添加。消息序列化为应用程序特定的 JSON 字符串。
获取用户 HGETALL user:{id}。
HGETALL user:2
获取 ID 为 2 的用户数据。
SMEMBERS user:2:rooms
这将返回 ID 为 2 的用户的聊天室 ID
ZREVRANGE room:{roomId} {offset_start} {offset_end}
。例如: ZREVRANGE room:1:2 0 50
这将返回 ID 为 1 和 2 的用户之间的私人房间的 0 偏移量的 50 条消息。