C#實(shí)現(xiàn)MQTT服務(wù)端與客戶端通訊功能
關(guān)于MQTT
MQTT(消息隊(duì)列遙測(cè)傳輸)是ISO 標(biāo)準(zhǔn)(ISO/IEC PRF 20922)下基于發(fā)布/訂閱范式的消息協(xié)議。它工作在 TCP/IP協(xié)議族上,是為硬件性能低下的遠(yuǎn)程設(shè)備以及網(wǎng)絡(luò)狀況糟糕的情況下而設(shè)計(jì)的發(fā)布/訂閱型消息協(xié)議,為此,它需要一個(gè)消息中間件 。
MQTT是一個(gè)基于客戶端-服務(wù)器的消息發(fā)布/訂閱傳輸協(xié)議。MQTT協(xié)議是輕量、簡(jiǎn)單、開(kāi)放和易于實(shí)現(xiàn)的,這些特點(diǎn)使它適用范圍非常廣泛。在很多情況下,包括受限的環(huán)境中,如:機(jī)器與機(jī)器(M2M)通信和物聯(lián)網(wǎng)(IoT)。其在,通過(guò)衛(wèi)星鏈路通信傳感器、偶爾撥號(hào)的醫(yī)療設(shè)備、智能家居、及一些小型化設(shè)備中已廣泛使用。
MQTT示例
注: 該示例演示統(tǒng)一使用WPF, 簡(jiǎn)單MVVM模式演示, 復(fù)制代碼需注意引用 NuGet包 GalaSoft
MQTT服務(wù)端建立:
演示界面:

演示代碼:
public class MainViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
ClientInsTances = new ObservableCollection<ClientInstance>();
}
IMqttServer mqttServer; //MQTT服務(wù)端實(shí)例
string message;
/// <summary>
/// 消息 用于界面顯示
/// </summary>
public string Message
{
get { return message; }
set { message = value; RaisePropertyChanged(); }
}
ObservableCollection<ClientInstance> clientInstances; //客戶端登陸緩存信息
/// <summary>
/// 客戶端實(shí)例
/// </summary>
public ObservableCollection<ClientInstance> ClientInsTances
{
get { return clientInstances; }
set { clientInstances = value; RaisePropertyChanged(); }
}
//開(kāi)啟MQTT服務(wù)
public void OpenMqttServer()
{
mqttServer = new MqttFactory().CreateMqttServer();
var options = new MqttServerOptions();
//攔截登錄
options.ConnectionValidator = c =>
{
try
{
Message += string.Format("用戶嘗試登錄:用戶ID:{0}\t用戶信息:{1}\t用戶密碼:{2}", c.ClientId, c.Username, c.Password) + "\r\n";
if (string.IsNullOrWhiteSpace(c.Username))
{
Message += string.Format("用戶:{0}登錄失敗,用戶信息為空", c.ClientId) + "\r\n";
c.ReturnCode = MQTTnet.Protocol.MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
return;
}
//解析用戶名和密碼,這個(gè)地方需要改成查找我們自己創(chuàng)建的用戶名和密碼。
if (c.Username == "admin" && c.Password == "123456")
{
c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted;
Message += c.ClientId + " 登錄成功" + "\r\n";
ClientInsTances.Add(new ClientInstance()
{
ClientID = c.ClientId,
UserName = c.Username,
PassWord = c.Password
});
return;
}
else
{
c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
Message += "用戶名密碼錯(cuò)誤登陸失敗" + "\r\n";
return;
}
}
catch (Exception ex)
{
Console.WriteLine("登錄失敗:" + ex.Message);
c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
return;
}
};
//攔截訂閱
options.SubscriptionInterceptor = async context =>
{
try
{
Message += "用戶" + context.ClientId + "訂閱" + "\r\n";
}
catch (Exception ex)
{
Console.WriteLine("訂閱失敗:" + ex.Message);
context.AcceptSubscription = false;
}
};
//攔截消息
options.ApplicationMessageInterceptor = context =>
{
try
{
//一般不需要處理消息攔截
// Console.WriteLine(Encoding.UTF8.GetString(context.ApplicationMessage.Payload));
}
catch (Exception ex)
{
Console.WriteLine("消息攔截:" + ex.Message);
}
};
mqttServer.ClientDisconnected += ClientDisconnected;
mqttServer.ClientConnected += MqttServer_ClientConnected;
mqttServer.Started += MqttServer_Started;
mqttServer.StartAsync(options);
}
private void MqttServer_Started(object sender, EventArgs e)
{
Message += "消息服務(wù)啟動(dòng)成功:任意鍵退出" + "\r\n";
}
private void MqttServer_ClientConnected(object sender, MqttClientConnectedEventArgs e)
{
//客戶端鏈接
Message += e.ClientId + "連接" + "\r\n";
}
private void ClientDisconnected(object sender, MqttClientDisconnectedEventArgs e)
{
//客戶端斷開(kāi)
Message += e.ClientId + "斷開(kāi)" + "\r\n";
}
/// <summary>
/// 客戶端推送信息 - 用于測(cè)試服務(wù)推送
/// </summary>
/// <param name="clientID"></param>
/// <param name="message"></param>
public void SendMessage(string clientID, string message)
{
mqttServer.PublishAsync(new MqttApplicationMessage
{
Topic = clientID,
QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
Retain = false,
Payload = Encoding.UTF8.GetBytes(message),
});
}
}添加MQTT 客戶端登陸實(shí)例, 用于保存客戶的登陸信息,如下:
演示界面:
/// <summary>
/// 登陸客戶端信息
/// </summary>
public class ClientInstance : ViewModelBase
{
private string clientID;
private string userName;
private string passWord;
/// <summary>
/// 識(shí)別ID
/// </summary>
public string ClientID
{
get { return clientID; }
set { clientID = value; RaisePropertyChanged(); }
}
/// <summary>
/// 賬戶
/// </summary>
public string UserName
{
get { return userName; }
set { userName = value; RaisePropertyChanged(); }
}
/// <summary>
/// 密碼
/// </summary>
public string PassWord
{
get { return passWord; }
set { passWord = value; RaisePropertyChanged(); }
}
}MQTT客戶端建立:
演示代碼:
public class MainViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
clientID = new Random().Next(999, 9999) + ""; //測(cè)試隨機(jī)生成ClientID
}
IMqttClient mqttClient; //MQTT客戶端實(shí)例
string clientID; //機(jī)器ID
string message;
public string Message //用于接收當(dāng)前 消息
{
get { return message; }
set { message = value; RaisePropertyChanged(); }
}
//開(kāi)啟MQTT連接
public async void SignMqttServer()
{
var options = new MqttClientOptionsBuilder()
.WithClientId(clientID) //傳遞ClientID
.WithTcpServer("127.0.0.1", 1883) //MQTT服務(wù)的地址
.WithCredentials("admin", "123456") //傳遞賬號(hào)密碼
.WithCleanSession()
.Build();
mqttClient = new MqttFactory().CreateMqttClient();// .CreateManagedMqttClient();
mqttClient.Connected += MqttClient_Connected;
mqttClient.Disconnected += MqttClient_Disconnected;
mqttClient.ApplicationMessageReceived += MqttClient_ApplicationMessageReceived; //創(chuàng)建消息接受事件
await mqttClient.ConnectAsync(options);
//await mqttClient.SubscribeAsync(clientID);
}
private void MqttClient_ApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
{
Message += "收到的信息:" + Encoding.UTF8.GetString(e.ApplicationMessage.Payload) + "\r\n";
}
private void MqttClient_Disconnected(object sender, MqttClientDisconnectedEventArgs e)
{
Message += "客戶端斷開(kāi)";
}
private void MqttClient_Connected(object sender, MqttClientConnectedEventArgs e)
{
Message += "客戶端已連接" + "\r\n";
mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(clientID).Build()); //關(guān)聯(lián)服務(wù)端訂閱, 用于接受服務(wù)端推送信息
}
}演示界面:

實(shí)際演示效果(GIF)

到此這篇關(guān)于C#實(shí)現(xiàn)MQTT服務(wù)端與客戶端通訊功能的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
c#入門(mén)之枚舉和結(jié)構(gòu)體使用詳解(控制臺(tái)接收字符串以相反的方向輸出)
這篇文章主要介紹了c#入門(mén)之枚舉和結(jié)構(gòu)體使用詳解,最后提供了編寫(xiě)控制臺(tái)應(yīng)用程序接收字符串并做相應(yīng)處理的小示例,需要的朋友可以參考下2014-04-04
C#與SQL連接:GridView控件對(duì)數(shù)據(jù)庫(kù)的操作
GridView控件操作方面的知識(shí),需要的朋友可以參考一下2013-02-02
C#學(xué)習(xí)教程之Socket的簡(jiǎn)單使用
這篇文章主要給大家介紹了關(guān)于C#學(xué)習(xí)教程之Socket的簡(jiǎn)單使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
C#客戶端程序調(diào)用外部程序的3種實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于C#客戶端程序調(diào)用外部程序的3種實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04

