近期要实现一个图片异步上传的需求,需要用到RabbitMQ,辅助客户端完成对高并发请求的处理。
一、安装Erlang-
由于RabbitMQ服务器是用Erlang语言编写,所以我们需要先安装Erlang环境,本文使用的版本是erl-24.1
-
下载地址: https://github.com/erlang/otp/releases/download/OTP-24.1/otp_win64_24.1.exe
-
下载完成后,双击exe完成安装。记录安装目录,默认路径:C:Program Fileserl-24.1
-
配置环境变量
路径:计算机–右键–属性–高级系统设置–环境变量–系统变量
step 1 新建:
变量名:ERLANG_HOME
变量值:C:Program Fileserl-24.1
step 2 在系统变量栏找到Path
新建值%ERLANG_HOME%bin
-
检测安装状态
Win+R输入cmd,打开命令提示符,输入erl,如下,Erlang安装结束。
- 本文使用的版本为rabbitmq-server-windows-3.9.8
下载地址:https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.9.8/rabbitmq-server-windows-3.9.8.zip - 解压到任意目录下,本文解压地址是 C:Program Files
- 配置环境变量
方式同上,在系统变量栏
step 1 新建:
变量名:RABBITMQ_SERVER
变量值:C:Program Filesrabbitmq_server-3.9.8
step 2 在系统变量栏找到Path
新建值%RABBITMQ_SERVER%sbin
- 安装页面管理工具
4.1 CMD命令进入sbin目录, 或直接在该目录内Shift+右键–>在此处打开命令窗口
4.2 输入 rabbitmq-plugins.bat enable rabbitmq_management
- 启动服务
命令窗输入rabbitmq-server.bat,或直接双节打开rabbitmq-server.bat
- 测试
浏览器输入 http://localhost:15672/ ,username和password都输入 guest,登录。
只有配置了账户后,才能通过IP+端口号的方式访问RabbitMQ。
- 在Admin栏右侧,点击Virtual Host新增virtual host
- 在Admin栏右侧,点击User新增用户
- 为新增账号添加权限,点击新增的用户名即可编辑权限
- 删除guest账号,点击guest用户名
- 删除guest后,会有弹窗,取消即可,退出当前账号
- 使用IP访问,并用新账号登录
- 如果登录失败可以尝试以下方案
方案一:将新增账户类型设置为Administrator,CMD命令,在sbin目录下输入
rabbitmqctl set_user_tags admin administrator
设置后重试登录。(admin为刚才新增的账户名)
方案二:为新增账户添加默认virtual host的权限
rabbitmqctl set_permissions -p / admin ‘.’ '.’ '.*'
设置后重试登录。(/ 为默认virtual host, admin为新增账号)
方案三:新建账号,并分配权限
rabbitmqctl add_user guest1 123456 (账号guest1 密码123456)
rabbitmqctl set_user_tags guest1 administrator (设置账号类型为administrator)
rabbitmqctl set_permissions -p / guest1 ‘.’ '.’ ‘.*’ (为guest1添加权限)
设置后重试登录。
- 创建队列
--------------------------------------------------------------------以下操作非必要---------------------------------------------------------------
- 创建Exchanges
- 配置自定义的Exchange,配置好后可以通过点击队列名,查看Binds情况
- 创建两个C#控制台项目(本文使用vs2019),分别作为消息发布者和消息订阅者。.Net framework框架版本选择为4.6.1
- 两个工程创建后,都需要添加RabbitMQ包。(安装过程有弹窗,确定即可)
- 消息发布者代码(publisher.cs):每隔1s,向队列TestQueue1发送一条消息
using System;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
namespace publisher
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory()
{
HostName = "192.168.123.29",
VirtualHost = "visual_knitting_machine",
UserName = "admin",
Password = "123456",
Port = 5672
};
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
for (int i = 1; i < 1000; i++)
{
channel.QueueDeclare(
queue: "TestQueue1",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null
);
string message = "Hello World! -- " + i.ToString();
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(
exchange: "myTestExchange", //如果没有创建Exchange,此处为空字符串
routingKey: "queue1_routingKey",//如果没有创建routingKey,此处为空字符串
basicProperties: null,
body: body
);
Console.WriteLine(" {0} Sent '{1}'", i.ToString(), message);
Thread.Sleep(1000);
}
}
}
}
}
}
4. 消息订阅者代码(consumer.cs):每隔0.2s,从队列消费一条消息
using System;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace consumer
{
class Program
{
static void Main(string[] args)
{
//禁用控制台快速编辑模式,防止窗口假死。假死后程序会阻塞,只有按回车才能恢复状态
ConsoleUtil.DisbleQuickEditMode();//注释后也不会影响测试
var factory = new ConnectionFactory()
{
HostName = "192.168.123.29",
VirtualHost = "visual_knitting_machine",
UserName = "admin",
Password = "123456",
Port = 5672
};
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
while (true)
{
channel.QueueDeclare(
queue: "TestQueue1",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null
);
//公平分发、同一时间只处理一个消息
channel.BasicQos(0, 1, false);
//构建消费者实例
var consumer = new EventingBasicConsumer(channel);
//消息接收后的事件委托
consumer.Received += (sender, e) =>
{
var body = e.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
//根据消息Tag手动确认消息被消费
channel.BasicAck(e.DeliveryTag, false);
if (!string.IsNullOrEmpty(message))
{
Console.WriteLine(" Received '{0}'", message);
}
};
//启动消费者
string consumerTAG = channel.BasicConsume(
queue: "TestQueue1",
autoAck: false,//关闭自动确认,避免一次性将消息全部消费
consumer: consumer
);
//根据消费者Tag断开当前消费者
channel.BasicCancel(consumerTAG);
Thread.Sleep(200);
}
}
}
}
}
}
- 控制台工具类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
public class ConsoleUtil
{
#region 设置控制台标题 禁用关闭按钮
[Dllimport("user32.dll", EntryPoint = "FindWindow")]
extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
[Dllimport("user32.dll", EntryPoint = "GetSystemMenu")]
extern static IntPtr GetSystemMenu(IntPtr hWnd, IntPtr bRevert);
[Dllimport("user32.dll", EntryPoint = "RemoveMenu")]
extern static IntPtr RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);
static void DisbleClosebtn()
{
IntPtr windowHandle = FindWindow(null, "控制台标题");
IntPtr closeMenu = GetSystemMenu(windowHandle, IntPtr.Zero);
uint SC_CLOSE = 0xF060;
RemoveMenu(closeMenu, SC_CLOSE, 0x0);
}
protected static void CloseConsole(object sender, ConsoleCancelEventArgs e)
{
Environment.Exit(0);
}
#endregion
#region 关闭控制台 快速编辑模式、插入模式
const int STD_INPUT_HANDLE = -10;
const uint ENABLE_QUICK_EDIT_MODE = 0x0040;
const uint ENABLE_INSERT_MODE = 0x0020;
[Dllimport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetStdHandle(int hConsoleHandle);
[Dllimport("kernel32.dll", SetLastError = true)]
internal static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint mode);
[Dllimport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint mode);
public static void DisbleQuickEditMode()
{
IntPtr hStdin = GetStdHandle(STD_INPUT_HANDLE);
uint mode;
GetConsoleMode(hStdin, out mode);
mode &= ~ENABLE_QUICK_EDIT_MODE;//移除快速编辑模式
mode &= ~ENABLE_INSERT_MODE; //移除插入模式
SetConsoleMode(hStdin, mode);
}
#endregion
#region 设置控制台颜色
static void WriteColorLine(string str, ConsoleColor colorF, ConsoleColor colorB)
{
ConsoleColor currentForegroundColor = Console.ForegroundColor;
ConsoleColor currentBackgroundColor = Console.BackgroundColor;
Console.ForegroundColor = colorF;
Console.BackgroundColor = colorB;
//Console.WriteLine(str);
Console.ForegroundColor = currentForegroundColor;
Console.BackgroundColor = currentBackgroundColor;
}
#endregion
}
看完记得点赞、评论、收藏哦~~


