上一篇我们初步设计了MQTT服务端
C#使用MQTT(一):MQTT服务端-CSDN博客
这里我们设计客户端MQTT Client,接上一篇
新建Windows窗体FormMqttClient
窗体FormMqttClient设计如图:
窗体FormMqttClient设计器相关代码如下
文件FormMqttClient.Designer.cs
namespace CultureDemo
{partial class FormMqttClient{/// <summary>/// Required designer variable./// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){this.rtxtMessage = new System.Windows.Forms.RichTextBox();this.label8 = new System.Windows.Forms.Label();this.btnPublish = new System.Windows.Forms.Button();this.btnSubscribe = new System.Windows.Forms.Button();this.txtContent = new System.Windows.Forms.TextBox();this.label5 = new System.Windows.Forms.Label();this.txtTopicPublish = new System.Windows.Forms.TextBox();this.label6 = new System.Windows.Forms.Label();this.txtTopic = new System.Windows.Forms.TextBox();this.label7 = new System.Windows.Forms.Label();this.btnDisconnect = new System.Windows.Forms.Button();this.btnConnect = new System.Windows.Forms.Button();this.txtClientId = new System.Windows.Forms.TextBox();this.label4 = new System.Windows.Forms.Label();this.txtUpwd = new System.Windows.Forms.TextBox();this.label3 = new System.Windows.Forms.Label();this.txtUserName = new System.Windows.Forms.TextBox();this.label2 = new System.Windows.Forms.Label();this.txtPort = new System.Windows.Forms.TextBox();this.label1 = new System.Windows.Forms.Label();this.txtIP = new System.Windows.Forms.TextBox();this.lb = new System.Windows.Forms.Label();this.SuspendLayout();// // rtxtMessage// this.rtxtMessage.Location = new System.Drawing.Point(239, 37);this.rtxtMessage.Name = "rtxtMessage";this.rtxtMessage.Size = new System.Drawing.Size(623, 411);this.rtxtMessage.TabIndex = 51;this.rtxtMessage.Text = "";// // label8// this.label8.AutoSize = true;this.label8.Location = new System.Drawing.Point(242, 18);this.label8.Name = "label8";this.label8.Size = new System.Drawing.Size(29, 12);this.label8.TabIndex = 50;this.label8.Text = "消息";// // btnPublish// this.btnPublish.Location = new System.Drawing.Point(117, 425);this.btnPublish.Name = "btnPublish";this.btnPublish.Size = new System.Drawing.Size(75, 23);this.btnPublish.TabIndex = 49;this.btnPublish.Text = "发布";this.btnPublish.UseVisualStyleBackColor = true;this.btnPublish.Click += new System.EventHandler(this.btnPublish_Click);// // btnSubscribe// this.btnSubscribe.Location = new System.Drawing.Point(117, 286);this.btnSubscribe.Name = "btnSubscribe";this.btnSubscribe.Size = new System.Drawing.Size(75, 23);this.btnSubscribe.TabIndex = 48;this.btnSubscribe.Text = "订阅";this.btnSubscribe.UseVisualStyleBackColor = true;this.btnSubscribe.Click += new System.EventHandler(this.btnSubscribe_Click);// // txtContent// this.txtContent.Location = new System.Drawing.Point(92, 377);this.txtContent.Name = "txtContent";this.txtContent.Size = new System.Drawing.Size(100, 21);this.txtContent.TabIndex = 47;// // label5// this.label5.AutoSize = true;this.label5.Location = new System.Drawing.Point(45, 380);this.label5.Name = "label5";this.label5.Size = new System.Drawing.Size(29, 12);this.label5.TabIndex = 46;this.label5.Text = "内容";// // txtTopicPublish// this.txtTopicPublish.Location = new System.Drawing.Point(92, 341);this.txtTopicPublish.Name = "txtTopicPublish";this.txtTopicPublish.Size = new System.Drawing.Size(100, 21);this.txtTopicPublish.TabIndex = 45;// // label6// this.label6.AutoSize = true;this.label6.Location = new System.Drawing.Point(45, 344);this.label6.Name = "label6";this.label6.Size = new System.Drawing.Size(29, 12);this.label6.TabIndex = 44;this.label6.Text = "主题";// // txtTopic// this.txtTopic.Location = new System.Drawing.Point(92, 248);this.txtTopic.Name = "txtTopic";this.txtTopic.Size = new System.Drawing.Size(100, 21);this.txtTopic.TabIndex = 43;// // label7// this.label7.AutoSize = true;this.label7.Location = new System.Drawing.Point(45, 251);this.label7.Name = "label7";this.label7.Size = new System.Drawing.Size(29, 12);this.label7.TabIndex = 42;this.label7.Text = "主题";// // btnDisconnect// this.btnDisconnect.Location = new System.Drawing.Point(130, 205);this.btnDisconnect.Name = "btnDisconnect";this.btnDisconnect.Size = new System.Drawing.Size(75, 23);this.btnDisconnect.TabIndex = 41;this.btnDisconnect.Text = "断开";this.btnDisconnect.UseVisualStyleBackColor = true;this.btnDisconnect.Click += new System.EventHandler(this.btnDisconnect_Click);// // btnConnect// this.btnConnect.Location = new System.Drawing.Point(36, 205);this.btnConnect.Name = "btnConnect";this.btnConnect.Size = new System.Drawing.Size(75, 23);this.btnConnect.TabIndex = 40;this.btnConnect.Text = "连接";this.btnConnect.UseVisualStyleBackColor = true;this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);// // txtClientId// this.txtClientId.Location = new System.Drawing.Point(67, 164);this.txtClientId.Name = "txtClientId";this.txtClientId.Size = new System.Drawing.Size(134, 21);this.txtClientId.TabIndex = 39;this.txtClientId.Text = "snake";// // label4// this.label4.AutoSize = true;this.label4.Location = new System.Drawing.Point(20, 167);this.label4.Name = "label4";this.label4.Size = new System.Drawing.Size(41, 12);this.label4.TabIndex = 38;this.label4.Text = "客户ID";// // txtUpwd// this.txtUpwd.Location = new System.Drawing.Point(67, 127);this.txtUpwd.Name = "txtUpwd";this.txtUpwd.Size = new System.Drawing.Size(134, 21);this.txtUpwd.TabIndex = 37;this.txtUpwd.Text = "1";// // label3// this.label3.AutoSize = true;this.label3.Location = new System.Drawing.Point(32, 130);this.label3.Name = "label3";this.label3.Size = new System.Drawing.Size(29, 12);this.label3.TabIndex = 36;this.label3.Text = "密码";// // txtUserName// this.txtUserName.Location = new System.Drawing.Point(67, 100);this.txtUserName.Name = "txtUserName";this.txtUserName.Size = new System.Drawing.Size(134, 21);this.txtUserName.TabIndex = 35;this.txtUserName.Text = "a";// // label2// this.label2.AutoSize = true;this.label2.Location = new System.Drawing.Point(32, 103);this.label2.Name = "label2";this.label2.Size = new System.Drawing.Size(29, 12);this.label2.TabIndex = 34;this.label2.Text = "账号";// // txtPort// this.txtPort.Location = new System.Drawing.Point(67, 64);this.txtPort.Name = "txtPort";this.txtPort.Size = new System.Drawing.Size(134, 21);this.txtPort.TabIndex = 33;this.txtPort.Text = "12345";// // label1// this.label1.AutoSize = true;this.label1.Location = new System.Drawing.Point(32, 67);this.label1.Name = "label1";this.label1.Size = new System.Drawing.Size(29, 12);this.label1.TabIndex = 32;this.label1.Text = "端口";// // txtIP// this.txtIP.Location = new System.Drawing.Point(67, 22);this.txtIP.Name = "txtIP";this.txtIP.Size = new System.Drawing.Size(134, 21);this.txtIP.TabIndex = 31;this.txtIP.Text = "127.0.0.1";// // lb// this.lb.AutoSize = true;this.lb.Location = new System.Drawing.Point(20, 25);this.lb.Name = "lb";this.lb.Size = new System.Drawing.Size(41, 12);this.lb.TabIndex = 30;this.lb.Text = "IP地址";// // FormMqttClient// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(874, 525);this.Controls.Add(this.rtxtMessage);this.Controls.Add(this.label8);this.Controls.Add(this.btnPublish);this.Controls.Add(this.btnSubscribe);this.Controls.Add(this.txtContent);this.Controls.Add(this.label5);this.Controls.Add(this.txtTopicPublish);this.Controls.Add(this.label6);this.Controls.Add(this.txtTopic);this.Controls.Add(this.label7);this.Controls.Add(this.btnDisconnect);this.Controls.Add(this.btnConnect);this.Controls.Add(this.txtClientId);this.Controls.Add(this.label4);this.Controls.Add(this.txtUpwd);this.Controls.Add(this.label3);this.Controls.Add(this.txtUserName);this.Controls.Add(this.label2);this.Controls.Add(this.txtPort);this.Controls.Add(this.label1);this.Controls.Add(this.txtIP);this.Controls.Add(this.lb);this.Name = "FormMqttClient";this.Text = "FormMqttClient";this.Load += new System.EventHandler(this.FormMqttClient_Load);this.ResumeLayout(false);this.PerformLayout();}#endregionprivate System.Windows.Forms.RichTextBox rtxtMessage;private System.Windows.Forms.Label label8;private System.Windows.Forms.Button btnPublish;private System.Windows.Forms.Button btnSubscribe;private System.Windows.Forms.TextBox txtContent;private System.Windows.Forms.Label label5;private System.Windows.Forms.TextBox txtTopicPublish;private System.Windows.Forms.Label label6;private System.Windows.Forms.TextBox txtTopic;private System.Windows.Forms.Label label7;private System.Windows.Forms.Button btnDisconnect;private System.Windows.Forms.Button btnConnect;private System.Windows.Forms.TextBox txtClientId;private System.Windows.Forms.Label label4;private System.Windows.Forms.TextBox txtUpwd;private System.Windows.Forms.Label label3;private System.Windows.Forms.TextBox txtUserName;private System.Windows.Forms.Label label2;private System.Windows.Forms.TextBox txtPort;private System.Windows.Forms.Label label1;private System.Windows.Forms.TextBox txtIP;private System.Windows.Forms.Label lb;}
}
窗体FormMqttClient程序代码如下:客户端程序
文件FormMqttClient.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MQTTnet;
using MQTTnet.Client;namespace CultureDemo
{public partial class FormMqttClient : Form{IMqttClient mqttClient;public FormMqttClient(){InitializeComponent();rtxtMessage.ReadOnly = true;}/// <summary>/// 打印相关消息/// </summary>/// <param name="contents"></param>private void DisplayMessage(string contents){if (!this.IsHandleCreated){return;}this.BeginInvoke(new Action(() =>{if (rtxtMessage.TextLength >= 40960){rtxtMessage.Clear();}rtxtMessage.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}->{contents}\n");rtxtMessage.ScrollToCaret();}));}private void FormMqttClient_Load(object sender, EventArgs e){mqttClient = new MqttFactory().CreateMqttClient();mqttClient.ConnectedAsync += MqttClient_ConnectedAsync;mqttClient.DisconnectedAsync += MqttClient_DisconnectedAsync;mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;}private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e){return Task.Run(new Action(() =>{string msg = e.ApplicationMessage.ConvertPayloadToString();DisplayMessage($"接收消息:{msg}\nQoS={e.ApplicationMessage.QualityOfServiceLevel}\n客户端={e.ClientId}\n主题:{e.ApplicationMessage.Topic}");}));}private Task MqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs e){return Task.Run(new Action(async () =>{DisplayMessage($"已断开到MQTT服务端的连接.尝试重新连接");try{await Task.Delay(3000);//MqttClientOptions options = new MqttClientOptions();//await mqttClient.ConnectAsync(options);await mqttClient.ReconnectAsync();}catch (Exception ex){DisplayMessage($"重新连接服务器失败:{ex.Message}");}}));}private Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs e){return Task.Run(new Action(() =>{DisplayMessage($"连接到MQTT服务端成功.{e.ConnectResult.AssignedClientIdentifier}");}));}private async void btnConnect_Click(object sender, EventArgs e){try{MqttClientOptionsBuilder mqttClientOptionBuild = new MqttClientOptionsBuilder().WithClientId(this.txtClientId.Text).WithTcpServer(this.txtIP.Text, int.Parse(this.txtPort.Text)).WithCredentials(this.txtUserName.Text, this.txtUpwd.Text);MqttClientOptions options = mqttClientOptionBuild.Build();//开启await mqttClient.ConnectAsync(options);}catch (Exception ex) {DisplayMessage($"连接服务端时出现异常:{ex.Message}");}}private async void btnDisconnect_Click(object sender, EventArgs e){if (mqttClient != null){if (mqttClient.IsConnected){await mqttClient.DisconnectAsync();}mqttClient.Dispose();}}private async void btnSubscribe_Click(object sender, EventArgs e){if (string.IsNullOrWhiteSpace(this.txtTopic.Text)){DisplayMessage(">>> 请输入主题");return;}//在 MQTT 中有三种 QoS 级别: QuanlityOfService//At most once(0) 最多一次//At least once(1) 至少一次//Exactly once(2) 恰好一次MqttClientSubscribeOptionsBuilder subscribeOptionsBuilder = new MqttClientSubscribeOptionsBuilder();MqttClientSubscribeOptions subscribeOption = subscribeOptionsBuilder.WithTopicFilter(this.txtTopic.Text).Build();await mqttClient.SubscribeAsync(subscribeOption);DisplayMessage($">>> 成功订阅主题【{txtTopic.Text}】");}private async void btnPublish_Click(object sender, EventArgs e){if (string.IsNullOrWhiteSpace(this.txtTopicPublish.Text)){DisplayMessage(">>> 请输入主题");return;}MqttClientPublishResult result = await mqttClient.PublishStringAsync(this.txtTopicPublish.Text,this.txtContent.Text,MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce);//恰好一次, QoS 级别1 DisplayMessage($"发布消息--主题:{this.txtTopicPublish.Text},消息:{this.txtContent.Text},结果: {result.ReasonCode}");}}
}
为了一个应用程序可以作为客户端和服务端,我们在Program.cs增加切换开关
选择作为MQTT服务端和MQTT客户端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;namespace CultureDemo
{static class Program{/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);DialogResult dialog = MessageBox.Show("请选择程序作为MQTT服务端还是客户端,选择\"是\"作为服务端,选择\"否\"作为客户端", "是否MQTT服务端", MessageBoxButtons.YesNo);if (dialog == DialogResult.Yes){Application.Run(new FormMqttServer());}else {Application.Run(new FormMqttClient());}}}
}