Bắt đầu từ bài học này chúng ta sẽ chuyển sang nội dung về lập trình truyền thông trong IoT. Chúng ta sẽ xem xét cách làm việc với một số giao thức IoT phổ biến. Trong loạt bài đầu tiên chúng ta sẽ làm quen với MQTT – một trong những giao thức tiêu chuẩn của IoT và cách làm việc với thư viện MQTTnet.
Để nắm được ý tưởng về cách thức hoạt động của MQTT, chúng ta sẽ cùng làm một bài thực hành.
Cài đặt MQTT broker
MQTT bắt buộc phải sử dụng một phần mềm trung gian độc lập gọi là broker. Cũng có thể hình dung broker là một server trung tâm của hệ thống phần mềm sử dụng MQTT. Mọi lệnh truyền từ client này sang client khác đều đi qua server trung tâm này.
Chúng ta có hai lựa chọn khi phát triển phần mềm sử dụng MQTT:
- sử dụng một broker sẵn có do một hãng thứ ba cung cấp trên đám mây;
- cài đặt broker server riêng trên máy chủ của mình.
Theo phương án thứ nhất, chúng ta có thể sử dụng dịch vụ của HiveMQ, EMQX, MQTT HQ. Các dịch vụ này đều cung cấp broker thử nghiệm miễn phí để thử nghiệm chương trình trước khi quyết định mua dịch vụ của họ:
- HiveMQ: broker.hivemq.com, TCP/1883, websocket/8000.
- EMQX: broker.emqx.io, TCP/1883, websocket/8083
- MQTT HQ: public.mqtthq.com, TCP/1883, websocket/8038
Theo phương án thứ hai, chúng ta có thể lựa chọn cài đặt một phần mềm broker trên chính máy tính của mình để thử nghiệm. Phần mềm broker miễn phí đa nền tảng dễ cài đặt và sử dụng nhất là Mosquitto. Bạn có thể tải bản cài của Mosquitto từ địa chỉ https://mosquitto.org/download/. Nếu sử dụng Windows, bạn cài đặt nó như một phần mềm bình thường. Sau khi cài đặt xong, Mosquitto sẽ hoạt động như một dịch vụ. Bạn không cần bất kỳ thao tác cấu hình nào.
Tạo dự án
MQTT hoạt động theo mô hình publish / subscribe. Do đó bạn cần tạo ít nhất 2 dự án, một dự án cho publisher, một dự án cho subscriber. Publisher và Subscriber được gọi chung là client.
Thực hiện theo các bước sau:
Bước 1. Tạo một solution trống trong Visual Studio
Bước 2. Thêm dự án ConsoleApp vào solution và đặt tên là Publisher. Dự án này sẽ tạo ra phần mềm phát lệnh
Bước 3. Thêm dự án ConsoleApp vào solution và đặt tên là Subscriber. Dự án này sẽ tạo ra phần mềm nhận lệnh.
Bước 4. Cấu hình để hai dự án trên có thể debug đồng thời khi ấn F5.
Bạn thu được solution với cấu trúc như sau:
Cài đặt thư viện MQTTnet
Trên .NET có một số thư viện thực thi giao thức MQTT. Nổi tiếng và phổ biến nhất là thư viện MQTTnet. Bạn có thể cài đặt nó từ NuGet như sau:
Bước 1. Click phải chuột vào tên solution và chọn Manage NuGet Packages for Solution.
Bước 2. Trong cửa sổ mở ra chọn tab Browse và gõ vào ô tìm kiếm “mqttnet”. Trong danh sách kết quả chọn gói MQTTnet.
Bước 3. Trong hộp chọn dự án bên phải tích chọn cả hai dự án và ấn Install.
Sau bước này, Visual Studio sẽ tự động cài đặt gói thư viện MQTTnet cho cả hai dự án Publisher và Subscriber. Bạn có thể xem kết quả trong cửa sổ Solution Explorer.
Viết code cho Publisher
Mở file Program.cs của dự án Publisher và viết code như sau:
using MQTTnet; using MQTTnet.Client; namespace Publisher; internal class Program { static async Task Main(string[] args) { Console.WriteLine("-- MQTT Publisher --"); var mqttFactory = new MqttFactory(); using var mqttClient = mqttFactory.CreateMqttClient(); var mqttClientOptions = new MqttClientOptionsBuilder() .WithTcpServer("broker.hivemq.com") .Build(); await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None); while (true) { Console.Write("Message >>> "); var payload = Console.ReadLine(); if (payload == "quit") break; var applicationMessage = new MqttApplicationMessageBuilder() .WithTopic("mype/test/command/1") .WithPayload(payload) .Build(); await mqttClient.PublishAsync(applicationMessage, CancellationToken.None); } await mqttClient.DisconnectAsync(); } }
Hoạt động của Publisher như sau:
- (1) khởi tạo MqttClient,
- (2) kết nối với broker,
- (3) cho người dùng nhập vào một chuỗi ký tự,
- (4) phát thông điệp theo chủ đề thiết lập sẵn tới broker,
- (5) lặp lại bước (3) cho đến khi người dùng nhập chuỗi “quit”,
- (6) ngắt kết nối với broker.
Publisher sử dụng dịch vụ MQTT trên đám mây của HiveMQ tại địa chỉ broker.hivemq.com với cổng mặc định (1883). Bạn có thể sử dụng bất kỳ dịch vụ nào khác thay thế.
Publisher này sẽ phát đi các thông điệp với chủ để “mype/test/command/1”. Trong mỗi thông điệp chứa một chuỗi ký tự do người dùng nhập vào. Chuỗi ký tự gửi trong thông điệp như vậy được gọi là payload. Payload có thể là bất kỳ dữ liệu nào, miễn là có thể chuyển thành chuỗi byte (thông qua quá trình serialization).
Thư viện MQTTnet hoàn toàn sử dụng các phương thức bất đồng bộ theo mô hình TAP. Do vậy, chúng ta sử dụng phiên bản bất đồng bộ của phương thức Main: static async Task Main.
Viết code cho Subscriber
Mở file Program.cs của dự án Subscriber và viết code như sau:
using MQTTnet; using MQTTnet.Client; using System.Text; namespace Subscriber; internal class Program { static async Task Main(string[] args) { Console.WriteLine("-- MQTT Subscriber --"); var mqttFactory = new MqttFactory(); using var mqttClient = mqttFactory.CreateMqttClient(); var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("broker.hivemq.com").Build(); mqttClient.ApplicationMessageReceivedAsync += OnMessageReceived; await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None); var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder() .WithTopicFilter( f => { f.WithTopic("mype/test/command/1"); }) .Build(); await mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None); Console.WriteLine("MQTT client subscribed to topic."); Thread.Sleep(-1); } static async Task OnMessageReceived(MqttApplicationMessageReceivedEventArgs e) { Console.WriteLine($"# Received message: {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}"); await Task.CompletedTask; } }
Hoạt động của Subscriber như sau:
- (1) Khởi tạo MqttClient với cùng broker như Publisher (broker.hivemq.com)
- (2) Chỉ định phương thức sẽ được thực thi khi nhận được thông điệp từ broker (phương thức OnMessageReceived)
- (3) Kết nối với broker
- (4) Đăng ký nhận thông điệp theo chủ đề “mype/test/command/1”. Chú ý rằng, chủ đề đăng ký phải trùng với chủ đề xuất bản. Nếu không Subscriber sẽ không nhận được thông điệp từ Publisher.
- (5) Dừng luồng chính với lời gọi Thread.Sleep(-1) vì chương trình đang thực thi ở chế độ bất đồng bộ. Nếu không dừng luồng chính, chương trình sẽ thoát ngay.
So với Publisher, Subscriber có nhiều điểm khác biệt:
- Publisher là bên chủ động phát thông điệp; Subscriber là bên thụ động nhận thông điệp.
- Publisher không đăng ký chủ đề; Subscriber phải đăng ký chủ đề.
Tương tự như bên Publisher, code của Subscriber cũng hoàn toàn sử dụng lời gọi bất đồng bộ theo mô hình TAP và phiên bản bất đồng bộ của Main.
Chạy thử nghiệm
Ấn F5 hoặc Ctrl+F5 để chạy thử nghiệm cả hai chương trình, bạn thu được kết quả như sau:
Như vậy, publisher và subscriber đã có thể trao đổi thông tin với nhau. Dữ liệu trao đổi trong trường hợp này là một chuỗi ký tự UTF-8 theo quy ước.
Giờ bạn quay trở lại Visual Studio và chạy debug thêm một bản nữa của Subscriber. Nhập một vài dòng vào publisher, bạn sẽ thu được kết quả như sau:
Như vậy, bạn có thể thấy, publisher gửi được thông điệp tới cả 2 subscriber, tức là truyền thông theo mô hình multicast giữa 1 publisher với nhiều subscriber. Đây là một điểm khác biệt rất lớn giữa MQTT với các giao thức hoạt động theo mô hình request / response.
Giờ bạn đóng các cửa sổ console, quay về giao diện Visual Studio và chỉnh chuỗi chủ đề trên Publisher thành “mype/test/command/2”.
Nếu bạn chạy debug lại sẽ thu được kết quả như sau:
Điều này có nghĩa là Subscriber không hề nhận được thông điệp từ Publisher. Như vậy có thể hình dung rằng, nếu Subscriber đăng ký nhận thông điệp theo chủ đề nào thì nó chỉ có thể nhận thông điệp theo đúng chủ đề đó. Các thông điệp theo chủ đề khác sẽ không được chuyển tiếp đến Subscriber. Nhiệm vụ chuyển tiếp thông điệp theo chủ đề như vậy do broker chịu trách nhiệm.
Điều này cũng cho phép chúng ta hình dung ra rằng, chủ đề hoạt động tương tự như một lệnh quy ước giữa Publisher và Subscriber. Subscriber sẽ chỉ nhận những mệnh lệnh xác định từ Publisher phù hợp. Khi này, payload trong thông điệp cũng có thể hình dung tương tự như tham số để thực hiện lệnh.
+ Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn.
+ Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.
+ Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.
Cảm ơn bạn!
Kết luận
Trong bài học này chúng ta đã làm bài thực hành lập trình cơ bản với giao thức MQTT trong .NET sử dụng thư viện MQTTnet. Qua đây cần lưu ý:
- MQTT hoạt động theo mô hình pub / sub, với một chương trình broker riêng biệt và các chương trình client tự phát triển
- Publisher và Subscriber cần thỏa thuận trước về chủ đề
- Một Publisher có thể truyền thông tin đồng thời cho nhiều Subscriber
Trong bài học tiếp theo chúng ta sẽ xem xét chi tiết về giao thức MQTT.