使用 C# 和 Redis Pub/Sub 创建一个非常简单的控制台聊天应用程序





5.00/5 (5投票s)
使用 C# (.NET Core) 和 Redis 的 pub/sub 功能创建一个非常简单的控制台聊天应用程序,代码仅 55 行。
引言
本文适合 Redis Pub/Sub 的初学者。实际上,Redis 本身在其 pub/sub 文档中有一个用 Ruby 编写的不错的聊天应用程序示例 在这里(不妨看一下),但在本文中,我们将学习 Redis pub/sub,并使用 C# (.NET Core) 和 Redis 创建一个非常简单的聊天应用程序(包含换行符和注释共 55 行代码),之后我们还将讨论从中需要注意的事项。
背景
Redis 是一个开源的、内存数据结构存储,用作数据库、缓存和消息代理。它是 NoSQL 数据库之一。基本上,它是一个键值存储,并带有一些其他强大功能(其中一个就是 pub/sub)。
要求
为了跟上本文的进度并亲自动手编写代码,我们需要准备好
-
Redis。我们可以从 Microsoft Azure 或 Amazon Web Services 获取现成的 Redis 服务器,或者,如果你不想注册任何云服务,也可以在自己的计算机上安装 Redis 服务器。这还假设你已经知道如何使用 -至少是基本操作 -
redis-cli
。 -
.NET Core。众所周知,.NET Core 可以在 Windows、Linux 和 macOS / OS X 上运行。
-
源代码编辑器或 IDE。当然,我们需要这个,但对于 Windows(或 Mac),推荐使用 Visual Studio。如果我们已经安装了 .NET Core,我们也可以选择 Visual Studio 以外的其他源代码编辑器。
Redis Pub/Sub 基础
引用自维基百科,发布/订阅是一种消息传递模式,消息的发送者(称为发布者)不会将消息直接编程发送给特定的接收者(称为订阅者),而是将发布的消息分类到不同的类别中,而不知道有哪些订阅者(如果有的话)。同样,订阅者表达对一个或多个类别的兴趣,并且只接收感兴趣的消息,而不知道有哪些发布者(如果有的话)。
正如我们之前提到的,Redis 不仅仅是一个键值服务器,它也是一个消息服务器。通过 Redis,我们可以实现发布/订阅。Redis 为其 pub/sub(或发布/订阅)功能提供了很好的文档 在这里。但简单来说,Redis 的发布/订阅功能使我们能够在进程之间实现快速的消息传递和通信。
需要注意的是,Redis pub/sub 与键空间无关。它的设计初衷是不在任何级别上干扰它,包括数据库编号。
Redis 提供了简单的命令来实现发布/订阅。在 Redis CLI 中,订阅频道的命令非常简单。
SUBSCRIBE channel_one channel_two
在上面的示例中,客户端订阅了名为 channel_one
和 channel_two
的频道。一个客户端可以订阅多个频道。
如果我们打开另一个客户端(redis-cli
或其他 Redis 交互工具),而不关闭用于订阅的客户端,然后尝试使用 PUBLISH
命令,如下所示。
PUBLISH channel_one "Hey Guys!"
消息将能被订阅者收到。我们可以从下面的示例(gif)中看到。
好了,关于基础知识就到这里。实际上,Redis 还有其他与 pub/sub 相关的命令,它们是用于取消订阅频道/频道的 UNSUBSCRIBE
,用于频道名称的模式匹配订阅(使用 glob 风格的模式)的 PSUBSCRIBE
,以及 PUNSUBSCRIBE
。现在,让我们开始创建我们非常简单的聊天应用程序。
创建简单的聊天应用程序
在本节中,我们将使用 C# 创建一个非常简单的聊天应用程序,代码量仅为 55 行。本文假设您正在使用 Visual Studio。
让我们开始吧。首先,创建一个 .NET Core 控制台应用程序,可以将其命名为“SimpleChatApp
”。之后,我们需要获取/安装这个 nuget 包:StackExchange.Redis,用于与 Redis 通信,这是 .NET 语言(C# 等)的 Redis 客户端库,我建议您查看其文档。
我们将一步一步来。第一步,我们需要建立与 Redis 的连接。
using StackExchange.Redis;
using System;
namespace SimpleChatApp
{
class Program
{
private const string RedisConnectionString = "localhost";
private static ConnectionMultiplexer connection =
ConnectionMultiplexer.Connect(RedisConnectionString);
private const string ChatChannel =
"Chat-Simple-Channel"; // Can be anything we want.
private static string userName = string.Empty;
static void Main()
{
Console.WriteLine("Hello World!");
}
}
}
需要知道的是,ConnectionMultiplexer
实现了 IDisposable
,通常情况下,我们需要在应用程序的整个生命周期内重用该对象。在上面的代码中,我们没有使用 using
块,因为在关闭控制台应用程序后,它会被自动释放。
对于连接字符串配置,我们可以使用 Microsoft Azure Cache 或其他 Redis 云服务,而不是使用 localhost。有关配置文档,请在此处 查看。
继续。在 Main()
方法中,编写以下代码。
static void Main()
{
// Enter name and put it into variable userName
Console.Write("Enter your name: ");
userName = Console.ReadLine();
// Create pub/sub
var pubsub = connection.GetSubscriber();
// Subscriber subscribes to a channel
pubsub.Subscribe(ChatChannel, (channel, message) => MessageAction(message));
// Notify subscriber(s) if you're joining
pubsub.Publish(ChatChannel, $"'{userName}' joined the chat room.");
// Messaging here
while (true)
{
pubsub.Publish(ChatChannel, $"{userName}: {Console.ReadLine()} " +
$"({DateTime.Now.Hour}:{DateTime.Now.Minute})");
}
}
private static void MessageAction(RedisValue message)
{
// We'll implement it later, to show the message.
throw new NotImplementedException();
}
从上面的代码可以看出,为了订阅,我们需要将频道名称作为第一个参数传递,然后将处理程序/回调作为第二个参数。对于第二个参数,我们传递一个带有两个参数(频道和消息)的 Action。对于这个 Action,我们创建了 MessageAction
。在这里我们不需要频道对象,因为我们只关心消息。对于发布消息,就像之前的 PUBLISH
命令一样,我们需要传递频道名称,然后是消息本身。
我们使用 MessageAction
来打印消息,让我们用下面的代码来编写我们的方法。
static void MessageAction(string message)
{
int initialCursorTop = Console.CursorTop;
int initialCursorLeft = Console.CursorLeft;
Console.MoveBufferArea(0, initialCursorTop, Console.WindowWidth,
1, 0, initialCursorTop + 1);
Console.CursorTop = initialCursorTop;
Console.CursorLeft = 0;
// Print the message here
Console.WriteLine(message);
Console.CursorTop = initialCursorTop + 1;
Console.CursorLeft = initialCursorLeft;
}
让我们把它们放在一起,代码看起来会是这样。
using StackExchange.Redis;
using System;
namespace SimpleChatApp
{
class Program
{
private const string RedisConnectionString = "localhost";
private static ConnectionMultiplexer connection =
ConnectionMultiplexer.Connect(RedisConnectionString);
private const string ChatChannel = "Chat-Simple-Channel";
private static string userName = string.Empty;
static void Main()
{
// Enter name and put it into variable userName
Console.Write("Enter your name: ");
userName = Console.ReadLine();
// Create pub/sub
var pubsub = connection.GetSubscriber();
// Subscriber subscribes to a channel
pubsub.Subscribe(ChatChannel,
(channel, message) => MessageAction(message));
// Notify subscriber(s) if you're joining
pubsub.Publish(ChatChannel, $"'{userName}' joined the chat room.");
// Messaging here
while (true)
{
pubsub.Publish(ChatChannel, $"{userName}: {Console.ReadLine()} " +
$"({DateTime.Now.Hour}:{DateTime.Now.Minute})");
}
}
static void MessageAction(string message)
{
int initialCursorTop = Console.CursorTop;
int initialCursorLeft = Console.CursorLeft;
Console.MoveBufferArea(0, initialCursorTop, Console.WindowWidth,
1, 0, initialCursorTop + 1);
Console.CursorTop = initialCursorTop;
Console.CursorLeft = 0;
// Print the message here
Console.WriteLine(message);
Console.CursorTop = initialCursorTop + 1;
Console.CursorLeft = initialCursorLeft;
}
}
}
就是这样!构建项目。
请注意,如果我们使用 .NET Core,可以在输出 DLL 目录(bin/Debug 或 bin/Release)中使用此命令通过命令提示符或终端(如果您使用的是 Linux)来运行应用程序。
dotnet SimpleChatApp.dll
让我们看看它是如何工作的。
我们已经创建了一个聊天应用程序,纯粹是为了好玩!只要它连接到 Redis(或云服务中的 Redis),我们就可以聊天。
需要考虑的事项
我们需要知道,默认情况下,使用此应用程序时,Redis 连接是按应用程序打开/创建的,这并不理想。如果我们使用 Microsoft Azure 服务或其他 Redis 云服务,那里对客户端连接数是有限制的。
还值得一提的是,StackExchange.Redis
客户端库默认打开两个到 Redis 的连接,一个用于交互式命令,一个用于 pub/sub。所以,这个应用程序会创建两个到 Redis 的连接(每个应用程序)。如果我们安装了 Redis,可以使用以下命令查看 Redis 连接的统计信息。
redis-cli --stat
请记住,这只是一个非常简单的聊天应用程序,但我们仍然可以很有趣地使用它,同时了解其局限性。如果我们使用客户端-服务器应用程序并将其托管在某个地方,会更好。
玩得开心! :)
历史
- 2017年12月21日:初始版本