最近项目需要用到消息的订阅发布,因此使用了MQTT方式实现。
MQTT介绍:MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的轻量级协议,该协议构建于TCP/IP协议之上,MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
MQTT传输的消息分为:主题(Topic)和负载(payload)两部分:
(1)Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload);
(2)payload,可以理解为消息的内容,是指订阅者具体要使用的内容。
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。
首先,在项目中引入MMQTT包:
1.在官网下载MMQTT包(此处用的4.3.0.0版本),将包copy到项目的libs文件夹中
2.在项目的“引用”那里右键,“添加引用”,将包添加进项目中。
本项目拿文件订阅发布为例,其中,消息发布部分:
#region MQTT发布
string serverIp = ConfigHelper.GetAppSettingsValue("ServerIP");
string serverPort = ConfigHelper.GetAppSettingsValue("ServerPort");
//创建客户端实例
MqttClient client = new MqttClient(serverIp, Convert.ToInt32(serverPort), false, null, null, MqttSslProtocols.TLSv1_2);
string clientId = Guid.NewGuid().ToString();
//输入用户名
string username = "admin";
//输入密码
string password = "admin";
//建立连接
client.Connect(clientId, username, password);
//判断文件是否存在
if (File.Exists(req.PhysicalPath + @"\" + req.StorageName))
{
//使用文件流下形式读写文件
using (FileStream fsRead = new FileStream(req.PhysicalPath + @"\" + req.StorageName, FileMode.Open))
{
int fsLen = (int)fsRead.Length;
byte[] heByte = new byte[fsLen];
int r = fsRead.Read(heByte, 0, heByte.Length);
string myStr = System.Text.Encoding.UTF8.GetString(heByte);
//文件名
string fileName = req.StorageName;
//发布主题
client.Publish(Const.PRE_TRANSFER + device.SerialNumber,
System.Text.Encoding.UTF8.GetBytes(string.Format("{0};{1}", myStr, fileName)),
MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
}
}
#endregion
ConfigHelper部分(获取appsettings中的value值):
public class ConfigHelper
{
///
/// 获取AppSettings里的Value值
///
///
///
public static string GetAppSettingValue(string keyName)
{
string result = string.Empty;
try
{
result = ConfigurationManager.AppSettings[keyName];
}
catch (Exception ex)
{
LogHelper.Error(string.Format("获取配置文件出错:{0}", ex.Message));
}
return result;
}
}
消息订阅部分:
引入M2MQTT
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
public class SubscribeFileTransfer
{
private string serverIp = ConfigHelper.GetAppSettingValue("ServerIP");
private string serverPort = ConfigHelper.GetAppSettingValue("ServerPort");
private string serialNumber = ConfigHelper.GetAppSettingValue("SerialNumber");
///
/// 订阅传输文件
///
public void SubscribeTransfer()
{
//创建客户端实例
MqttClient client = new MqttClient(serverIp, Convert.ToInt32(serverPort), false, null, null, MqttSslProtocols.TLSv1_2);
string clientId = Guid.NewGuid().ToString();
string username = "admin";
string password = "admin";
//建立连接
client.Connect(clientId, username, password);
//订阅主题
client.Subscribe(new string[] {Const.PRE_TRANSFER + serialNumber}, new byte[] {MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE});
//+=可以存储多个事件方法,这些方法称为订阅者
client.MqttMsgPublishReceived += client_MqttMsgPublishTransferReceived;
}
///
/// 传输文件订阅相应
///
///
///
void client_MqttMsgPublishTransferReceived(object sender, MqttMsgPublishEventArgs e)
{
//处理接收到的消息
string msg = System.Text.Encoding.Default.GetString(e.Message);
//分割出文件名
string fileName = msg.Substring(msg.LastIndexOf(";") + 1, msg.Length - msg.LastIndexOf(";") - 1);
//分割出文件内容
byte[] fileContent = Encoding.UTF8.GetBytes(msg.Substring(0, msg.LastIndexOf(";")));
//文件路径
string filePath = @"D:\" + fileName;
//写入文件
using (FileStream fsWrite = new FileStream(filePath, FileMode.Append))
{
fsWrite.Write(fileContent, 0, fileContent.Length);
}
SqlHelper sqlHelper = new SqlHelper(AppSettings.CenterDatabaseConnStr);
//更新数据库,修改字段issend为true
string sql = string.Format("UPDATE DeviceFileTransfer set IsSend = 'true', SendTime = '{0}' where SerialNumber = '{1}'", DateTime.Now.ToString(), serialNumber);
int count = sqlHelper.ExecuteSql(sql);
if (count > 0)
{
LogHelper.Info("文件传输成功!");
}
}
}