-
Notifications
You must be signed in to change notification settings - Fork 0
MS_Mosquitto
- 戻る(IoT関連の通信プロトコル)
- Mosquitto
- RabbitMQ
MQTT ブローカーの OSS
補足(MQTT と Mosquitto の関係): MQTT は
IoT 向けの軽量なメッセージング プロトコル(OASIS 標準)、
Mosquitto はそのブローカー(サーバー)実装の代表例である
(Eclipse Foundation のプロジェクト)。RabbitMQ と並べられているが、性格はかなり違う。
Mosquitto RabbitMQ 主プロトコル MQTT AMQP(MQTT はプラグイン) 想定 多数の非力なデバイス サーバー間の業務メッセージング モデル Topic への Pub/Sub Exchange / Binding / Queue 永続化 軽量(既定はメモリ) キューの永続化が前提 フットプリント 極小(Raspberry Pi でも動く) 大きい(Erlang VM) 「センサーが大量にあって、細かいメッセージを絶え間なく送る」なら MQTT、
「業務処理を確実に非同期化したい」なら AMQP、という住み分けになる。
送信する人
受信する人
送受信対象のメッセージ
キュー
-
トピック
-
/から始まる Unicode UTF-8 文字列 - 全長 65535 バイト以下
- ヌル文字を含まない
-
-
ワイルドカード
-
#:マルチレベル・ワイルドカード(その階層以下の全トピック文字列と一致) -
+:シングルレベル・ワイルドカード(当該階層以下の全トピック文字列と一致)
-
補足(Topic 設計が MQTT の要): MQTT には
RabbitMQ のような Exchange の種別が無く、
すべてが Topic の階層構造で表現される。
したがって、Topic の命名がそのままルーティング設計になる。factory/line1/machine3/temperature │ │ │ └ 何の値か │ │ └ どの機器か │ └ どのラインか └ どの拠点か factory/line1/+/temperature → line1 の全機器の温度 factory/line1/# → line1 配下のすべて粗いところから細かいところへ並べるのが原則で、
逆順にするとワイルドカードで絞れなくなる。
また、後から階層を増やすのは難しいため、
最初に将来の拡張を織り込む必要がある。なお、原文の「
/から始まる」は慣例であり、
仕様上の必須ではない(先頭の/は空の階層を作るため、
実務では付けない方が多い)。補足(QoS): 原文のコードに出てくる QoS も MQTT の中核概念である。
QoS 保証 用途 0 At most once(届かないかも) 頻繁なセンサー値。落ちても次が来る 1 At least once(重複するかも) 一般的な選択。冪等性が必要 2 Exactly once(1 回だけ) 課金・制御など。最も遅い IoT では大半が QoS 0 か 1 で足りる。
QoS 2 は往復が 4 回必要で、大量デバイスでは負荷になる。
http://mosquitto.org/download/
>cd C:\Program Files\Mosquitto
>mosquitto -v
- 受信
全トピックを受信
>cd C:\Program Files\Mosquitto
>mosquitto_sub -h 127.0.0.1 -t "#" -v
- 送信
test トピックに送信
>cd C:\Program Files\Mosquitto
>mosquitto_pub -h 127.0.0.1 -t test -m "hoge"
- インストール
- リポジトリを追加
$ sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa- サーバー&クライアント
$ sudo apt-get install mosquitto mosquitto-clients-
ブローカー起動
不要 -
送受信
Windowsと同じ。 -
参考
- Mosquitto(MQTT Broker) のインストール - Qiita
https://qiita.com/n-yamanaka/items/73e4d3022186732b4e88
- Mosquitto(MQTT Broker) のインストール - Qiita
-
インストール
- サーバー
$ sudo apt-get install mosquitto- クライアント
$ sudo apt-get install mosquitto-clients-
ブローカー起動
不要 -
送受信
Windowsと同じ。 -
参考
- Raspberry Pi で IoT(MQTT で遠隔操作編 その1)MQTT での通信 – 株式会社インデペンデンスシステムズ横浜
http://independence-sys.net/main/?p=4054
- Raspberry Pi で IoT(MQTT で遠隔操作編 その1)MQTT での通信 – 株式会社インデペンデンスシステムズ横浜
ミドルウェアなので、Dockerの作法で動かせるっぽい。
(ただし、コンフィグ・ファイルの準備は必要)
https://github.com/OpenTouryoProject/DxCommon/tree/develop/Edge/Mosquitto/IaC
- 参考
-
MQTT を使ってみよう - Crieit
https://crieit.net/posts/MQTT -
Docker で MQTT 通信|竹のしんのテック日記
https://take6shin-tech-diary.com/mqtt-docker/ -
mosquitto(MQTT broker) の構築手順 | SINETStream
https://www.sinetstream.net/server/brokers/mosquitto%E6%A7%8B%E7%AF%89%E6%89%8B%E9%A0%86.html -
Qiita
- Docker で Mosquitto を動かして MQTT と WebSocket 通信してみる
https://qiita.com/danishi/items/bac267e85bc01523f385 - mosquitto を docker-compose で動かす
https://qiita.com/github0013@github/items/7c410216b74f29919da8
- Docker で Mosquitto を動かして MQTT と WebSocket 通信してみる
-
...
- Azure:Azure IoT Hub
- AWS:AWS IoT Core(ブリッジ機能)
- GCP:Cloud Pub/Sub?
移行メモ: 原文の 2 行目は「Azure:AWS IoT Core」となっていたが、
AWS の誤記と判断し修正した。
補足(マネージド サービスとの違い): Azure IoT Hub は
MQTT を話せるが、汎用の MQTT ブローカーではない点に注意が要る。
Mosquitto Azure IoT Hub Topic 自由に設計できる 固定( devices/{id}/messages/...)デバイス間の Pub/Sub できる できない(必ずクラウド経由) デバイス管理 無し(自前) デバイス ツイン、DPS、双方向通信 認証 自前で構成 デバイスごとの ID と証明書を管理 つまり IoT Hub は「MQTT 互換の入口を持つデバイス管理基盤」であり、
既存の MQTT アプリをそのまま繋ぐ用途には向かない。
現場に Mosquitto を置き、
IoT Edge でクラウドへ橋渡しする構成が
実際にはよく採られる。
-
Linux
-
Mosquitto で Username と Password を使う - Qiita
https://qiita.com/ekzemplaro/items/77bfa6274cbddd4b5624 -
Mosquitto(MQTT Broker) のインストール - Qiita > パスワード認証
https://qiita.com/n-yamanaka/items/73e4d3022186732b4e88
-
-
Windows
- mosquitto でパスワード認証の設定をする | コーヒー飲みながら仕事したい
https://coffee-nominagara.com/2018-09-25-141304
- mosquitto でパスワード認証の設定をする | コーヒー飲みながら仕事したい
-
サーバー認証とクライアント認証の両方が可能。
-
Linux
- Mosquitto(MQTT Broker) のインストール - Qiita > Mosquitto-TLS
https://qiita.com/n-yamanaka/items/73e4d3022186732b4e88
- Mosquitto(MQTT Broker) のインストール - Qiita > Mosquitto-TLS
-
Windows
- mosquitto で OpenSSL を用いて TLS 接続する | コーヒー飲みながら仕事したい
https://coffee-nominagara.com/2018-03-07-185728
- mosquitto で OpenSSL を用いて TLS 接続する | コーヒー飲みながら仕事したい
最近、更新頻度が落ちてきている。
-
認証フル実装は、チュートリアル側を参照。
- 受信
using System;
using System.Text;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
namespace M2MqttSub
{
class Program
{
static void Main(string[] args)
{
var client = new MqttClient("127.0.0.1");
client.MqttMsgPublishReceived += (sender, eventArgs) =>
{
var msg = Encoding.UTF8.GetString(eventArgs.Message);
var topic = eventArgs.Topic;
Console.WriteLine(topic + ", " + msg);
};
var ret = client.Connect(Guid.NewGuid().ToString());
Console.WriteLine("Connected with result code {0}", ret);
client.Subscribe(new[] { "test" }, new[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
while (client.IsConnected)
{
}
}
}
}- 送信
using System;
using System.Text;
using uPLibrary.Networking.M2Mqtt;
namespace M2MqttPub
{
class Program
{
static void Main(string[] args)
{
var client = new MqttClient("127.0.0.1");
var ret = client.Connect(Guid.NewGuid().ToString());
Console.WriteLine("Connected with result code {0}", ret);
while (client.IsConnected)
{
var msg = "Test message from Publisher " + DateTime.Now;
client.Publish("test", Encoding.UTF8.GetBytes(msg), 0, true);
Console.WriteLine("Message published.");
System.Threading.Thread.Sleep(1500);
}
}
}
}補足(最新化): 原文の見立てのとおり、Paho M2Mqtt は
現在ほぼ更新されていない(アーカイブ状態)。
新規開発では次の MQTTnet を選ぶこと。また、受信側の
while (client.IsConnected) { }は
CPU を 100% 使い切るビジーループである。
サンプルとしては動くが、実装では
Console.ReadLine()やManualResetEventで待つべき
(後述の MQTTnet の例はそうなっている)。
更新が頻繁で、トータル・ダウンロードが Paho M2Mqtt の4倍以上
-
以下は認証フル実装だが、証明書検証を無効化している。
CertificateValidationHandler で原因を見ると、
SslPolicyErrors.RemoteCertificateChainErrorsが出ている。- 受信
using System;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Receiving;
using System.Security.Cryptography.X509Certificates;
namespace msqt_sub
{
class Program
{
private static IMqttClient mqttClient = null;
static async Task Main(string[] args)
{
X509Certificate2 ca = new X509Certificate2("ca.crt");
X509Certificate2 cli = new X509Certificate2("client.pfx", "xxxxx");
var factory = new MqttFactory();
Program.mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithClientId("ef3614fca42b32d3")
.WithTcpServer("localhost", 8883)
.WithCredentials("guest", "guest")
.WithTls(new MqttClientOptionsBuilderTlsParameters(){
UseTls = true,
SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
AllowUntrustedCertificates = true,
//CertificateValidationCallback = (a, b, c, d) => true,
CertificateValidationHandler = (o) =>
{
Console.WriteLine(o.ToString());
return true;
},
Certificates = new List<X509Certificate>()
{
ca, cli
}
})
.Build();
// 接続後のイベントハンドラの設定
Program.mqttClient.ApplicationMessageReceivedHandler
= new MqttApplicationMessageReceivedHandlerDelegate(OnAppMessage);
Program.mqttClient.ConnectedHandler
= new MqttClientConnectedHandlerDelegate(OnConnected);
// 接続
await Program.mqttClient.ConnectAsync(options);
// 待機
Console.ReadLine();
}
static private async void OnConnected(MqttClientConnectedEventArgs e) {
await Program.mqttClient.SubscribeAsync(
new TopicFilterBuilder()
.WithTopic("test").Build());
}
static private void OnAppMessage(MqttApplicationMessageReceivedEventArgs e)
{
string payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
Console.WriteLine(payload);
}
}
}- 送信
using System;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using System.Security.Cryptography.X509Certificates;
namespace msqt_pub
{
class Program
{
private static IMqttClient mqttClient = null;
static async Task Main(string[] args)
{
X509Certificate2 ca = new X509Certificate2("ca.crt");
X509Certificate2 cli = new X509Certificate2("client.pfx", "xxxxx");
var factory = new MqttFactory();
Program.mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithClientId("ef3614fca42b32d3")
.WithTcpServer("localhost", 8883)
.WithCredentials("guest", "guest")
.WithTls(new MqttClientOptionsBuilderTlsParameters(){
UseTls = true,
SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
AllowUntrustedCertificates = true,
//CertificateValidationCallback = (a, b, c, d) => true,
CertificateValidationHandler = (o) =>
{
Console.WriteLine(o.ToString());
return true;
},
Certificates = new List<X509Certificate>()
{
ca, cli
}
})
.Build();
// 接続
await Program.mqttClient.ConnectAsync(options);
// メッセージの送信するための設定
var message = new MqttApplicationMessageBuilder()
.WithTopic("test")
.WithPayload("hoge")
.WithExactlyOnceQoS()
.Build();
// メッセージの送信 publish
await Program.mqttClient.PublishAsync(message);
}
}
}- 参考
補足(証明書検証の無効化について):
AllowUntrustedCertificates = trueと
CertificateValidationHandlerで常にtrueを返す実装は、
検証を完全に無効化しているため、中間者攻撃に対して無防備になる。
原文も「無効化している」と明記しているとおり検証用の便法であり、
本番では必ず外すこと。
RemoteCertificateChainErrorsが出る原因は、たいてい
- 自己署名 CA が信頼されたルート証明機関に入っていない、
- サーバー証明書の CN / SAN がホスト名と一致しない、
のどちらかである。
原文のチュートリアルでも、
CA を証明書ストアに入れる手順が繰り返し出てくる。補足(最新化): MQTTnet は v4 以降で API が大きく変わっており、
上記のコードはそのままではビルドできない。
v3(原文) v4 以降 MqttClientOptionsBuilderTlsParameters.WithTlsOptions(o => ...)ApplicationMessageReceivedHandlerApplicationMessageReceivedAsyncイベントTopicFilterBuilderMqttTopicFilterBuilderMqttFactoryMqttClientFactory
証明書認証(サーバー認証とクライアント認証)+パスワード認証を構成し、
Paho M2Mqtt、MQTTnet からアクセスする。
- 認証局の証明書を作成する。
>openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
Generating a RSA private key
................................................+++++
............+++++
writing new private key to 'ca.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:hogeca
Email Address []:
-
サーバー証明書
- RSA 鍵の作成
>openssl genrsa -out server.key 2048
- 証明書要求の作成
>openssl req -out server.csr -key server.key -new
(略)
Common Name (e.g. server FQDN or YOUR name) []:localhost
- サーバー証明書の発行
>openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
Signature ok
subject=C = JP, ST = Some-State, O = Internet Widgits Pty Ltd, CN = localhost
Getting CA Private Key
Enter pass phrase for ca.key:
-
証明書ファイルの配置
証明書ファイルをインストール・ディレクトリ直下の certs ディレクトリに配置 -
サーバー証明書の設定
mosquitto.conf の先頭に以下を追加
listener 8883
cafile ./certs/ca.crt
certfile ./certs/server.crt
keyfile ./certs/server.key
allow_anonymous true
- 動作確認を行う。
- conf を指定してブローカー起動
>cd C:\Program Files\Mosquitto
>mosquitto -v -c mosquitto.conf
-
送受信
- 受信
>mosquitto_sub -h localhost -t "#" -v -d -p 8883 --cafile <ca.crtのパス>
- 送信
>mosquitto_pub -h localhost -t test -m "hoge" -d -p 8883 --cafile <ca.crtのパス>
-
ハマりどころ
-
認証局の CN とサーバーの CN が同じ場合、以下のエラーが表示される。
- SSL routines:tls_process_server_certificate:certificate verify failed
- SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
-
Connection error: Connection Refused: not authorised.が出る。
「allow_anonymous true」を設定ファイルに追加する。
-
補足(この「ハマりどころ」は重要): CA の CN とサーバーの CN を
同じにしてはならないという指摘は、自己署名 CA を使う際に
極めて頻繁に踏む落とし穴である。
証明書チェーンの検証で、CA 自身とサーバー証明書が
区別できなくなるために失敗する。原文が CA を
hogeca、サーバーをlocalhostと
意図的に分けているのはこのためである。なお、現在の OpenSSL / クライアントでは CN ではなく
SAN(Subject Alternative Name)が必須である。
CN だけの証明書は多くのクライアントで拒否されるため、
証明書要求時に SAN を付ける必要がある。openssl req -out server.csr -key server.key -new \ -addext "subjectAltName = DNS:localhost,IP:127.0.0.1"
-
クライアント認証
- RSA 鍵の作成
>openssl genrsa -out client.key 2048
- 証明書要求の作成
>openssl req -out client.csr -key client.key -new
(略)
Common Name (e.g. server FQDN or YOUR name) []:hogecli
- クライアント証明書の発行
>openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
-
証明書ファイルの配置
証明書ファイルをインストール・ディレクトリ直下の certs ディレクトリに配置 -
クライアント証明書の設定
mosquitto.conf に以下を追加
require_certificate true
- 動作確認を行う。
- conf を指定してブローカー起動
>mosquitto -v -c mosquitto.conf
- 送受信
前述の送受信コマンドに以下を追加して実行する。
--cert <client.crtのパス> --key <client.keyのパス>
- ハマりどころ
...
- パスワードファイルを生成
>cd C:\Program Files\Mosquitto
>mosquitto_passwd -c pwfile guest
Password:
Reenter password:
- パスワード認証の有効化
mosquitto.conf の allow_anonymous 周辺に修正・追記
allow_anonymous false
password_file /etc/mosquitto/pwfile
- 動作確認を行う。
- conf を指定してブローカー起動
>mosquitto -v -c mosquitto.conf
- 送受信
前述の送受信コマンドに以下を追加して実行する。
-u guest -P guest
- ハマりどころ
パスワードは「-p」ではなく「-P」で指定する。
補足: 小文字の
-pはポート番号の指定である。
-p guestと書くと「ポート番号 guest」と解釈されてエラーになる。
-
クライアント証明書を、
*.pfxに変換する必要がありそう。 -
pkcs12 クライアント証明書(
*.pfx)を合成
>openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt
Enter Export Password:
Verifying - Enter Export Password:
-
認証局の証明書(ca.crt)は、証明書ストアの
信頼されたルート証明機関に入れておく必要がある。 -
証明書やパスワードの追加実装を行う。
X509Certificate2 ca = new X509Certificate2("ca.crt");
X509Certificate2 cli = new X509Certificate2("client.pfx", "xxxxx");
var client = new MqttClient("localhost", 8883, true, ca, cli, MqttSslProtocols.TLSv1_2);
client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
var ret = client.Connect(Guid.NewGuid().ToString(), "guest", "guest");-
デバッグ実行で動作確認
Windows は Publisher だけ動作確認済み。 -
参考
- Stack Overflow
- A call to SSPI failed, see inner exception paho m2mqtt Dot.Net(c#) client SSL/TLS connection
https://stackoverflow.com/questions/43993106/a-call-to-sspi-failed-see-inner-exception-paho-m2mqtt-dot-netc-client-ssl-tl - self signed x509 certificate issue in MQTT mosquitto using c#
https://stackoverflow.com/questions/31653754/self-signed-x509-certificate-issue-in-mqtt-mosquitto-using-c-sharp
- A call to SSPI failed, see inner exception paho m2mqtt Dot.Net(c#) client SSL/TLS connection
- Stack Overflow
補足(なぜ
*.pfxが必要か): .NET のX509Certificate2は
秘密鍵を含んだ形式を求める。
OpenSSL が出す*.crt(証明書のみ)と*.key(秘密鍵)は別ファイルなので、
PKCS#12(*.pfx/*.p12)に合成する必要がある。client.crt(証明書) ┐ ├──▶ client.pfx(.NET が読める) client.key(秘密鍵) ┘なお .NET 5 以降では
X509Certificate2.CreateFromPemFile()で
PEM から直接読めるようになっており、変換は必須ではなくなった。
コチラの実装で動作すると思う。
- Linux で動作確認済み。
- Windows は Publisher だけ動作確認済み。
-
基本的に、Windowsと同じ。
-
以下のように表示される場合、sudo を付ける。
req: Can't open "ファイル名" for writing, Permission denied
- key ファイルに権限付与
mosquitto に読み取り権限が無いらしい。
sudo chmod 644 server.key- ファイル設定
パスの指定方法が異なる。
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
allow_anonymous true
- 後は、以下で再起動。
$ sudo systemctl restart mosquitto- テストを行う。
※ ca_certificates フォルダがあったので、
CA のファイルはそちらに配置した方が良いカモ。
- ca.key
- ca.crt
補足(秘密鍵の権限):
chmod 644 server.keyは
秘密鍵を誰でも読める状態にするため、検証以外では避けるべきである。
正しくは所有者を mosquitto にして 640 にする。sudo chown root:mosquitto /etc/mosquitto/certs/server.key sudo chmod 640 /etc/mosquitto/certs/server.keyまた、原文が「CA のファイルは ca_certificates フォルダの方が良いカモ」と
述べているとおり、CA の秘密鍵(ca.key)はサーバーに置くべきではない
(証明書の発行元が漏れると、任意の証明書を偽造されるため)。
発行作業は別の安全な場所で行い、
サーバーにはca.crtだけを配置するのが正しい。
-
基本的に、Windowsと同じ。
-
以下のように表示される場合、sudo を付ける。
req: Can't open "ファイル名" for writing, Permission denied
- key ファイルに権限付与
mosquitto に読み取り権限が無いらしい。
sudo chmod 644 client.key- ファイル設定
以下を追記
require_certificate true
- 後は、以下で再起動。
$ sudo systemctl restart mosquitto- テストを行う。
-
基本的に、Windowsと同じ。
-
以下のように表示される場合、sudo を付ける。
Error: Unable to open file pwfile for writing. Permission denied.
- ファイル設定
mosquitto.conf の allow_anonymous 周辺に修正・追記
allow_anonymous false
password_file ./pwfile
- 後は、以下で再起動。
$ sudo systemctl restart mosquitto- テストを行う。
-
基本的に、Windowsと同じ。
-
/dev/msqt_pubとか言うフォルダを作成 -
プロジェクトを作成し
$ dotnet new console-
VS Code で msqt_pub フォルダを開く
-
必要に応じてエクステンションをインストール
- CSharp for Visual Studio Codeをインストール
- NuGet Package Manager をインストール
- NuGet で M2MqttDotnetCore をインストール
-
Program.cs にコチラの送信処理を実装
-
認証局の証明書(ca.crt)は、証明書ストアの
信頼されたルート証明機関に入れておく必要がある。 -
証明書やパスワードの追加実装を行う。
-
デバッグ実行で動作確認
コチラの実装で動作した。
正規の CN、場合によっては、
証明書ストアへの登録が必要なのかもしれない。
-
eclipse/mosquitto: Eclipse Mosquitto - An open source MQTT broker
https://github.com/eclipse/mosquitto -
MQTT で始める IoT デバイスの作り方
第1回:「MQTT」を知り「Mosquitto」を導入する:
MQTT で始める IoT デバイスづくり(1/3 ページ) - MONOist
https://monoist.atmarkit.co.jp/mn/articles/1605/23/news017.html
- Raspberry Pi で mosquitto を使う
https://qiita.com/ekzemplaro/items/ab90dd630c3ad8e819ab - RaspberryPi に Docker で Mosquitto を立てて、MQTT と Websockets
https://qiita.com/hilucky/items/42492e7ef5706b718bbb
- M2Mqtt を使用した MQTT のクライアントサンプル | OPC Diary
https://opcdiary.net/?p=28785 - C# (.net) で使える MQTT クライアント (Paho M2Mqtt) - スケ郎のお話
https://www.sukerou.com/2018/08/c-net-mqtt-paho-m2mqtt.html - 【MQTTnet】C# で MQTT を扱う - 地底人 newbie の気まぐれ
https://www.rect29.com/entry/2021/01/17/234306
Tags: 移行, 通信技術, .NET開発, IoT
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。