c# - 在不使用堆栈的情况下创建精简 MQTT 发布者(操作方法)
问题描述
我之前对谷歌的研究把我带到了这个页面:https ://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html 在这里我找到了一些信息……我开始尝试。测试设置是针对当地蚊子的。到目前为止这工作(它运行没有错误),但如果我发送 PUBLISH 消息,我会断开与蚊子的连接。
[编辑] 所以最大的问题是,消息有什么问题。
short summary as far as I understood:
[|] a Byte with High and Low 4 bits
[[|][|]] a word
{} a complex Byte data
Message for connect:
[1|0][0|0] … connect=1 , 0 length since no data
Message for publish:
[3,0]{LEN}{DATA} ...
with {LEN}=[0xxx|xxxx] with bit7=0 … for a len <127 Bytes
or {LEN}=[1xxx|xxxx][0xxx|xxxx] with Byte1 Bit7=1 … for a len >127 Bytes and <128^2
or {LEN}=[1xxx|xxxx][1xxx|xxxx][0xxx|xxx] with Byte1+2 Bit7=1 … for a len >127^2 Bytes and <128^3
with {data}=[[][]]{topic}{value}
[[][]] = Len of topic
{Topic}=UTF8 string (e.g. 'demo/target') as Byte
{value}=UTF8 string (e.g. a json or a simple text like'Hello world.') as byte
您可能想知道为什么我要对实现进行硬编码……这是为了理解功能。我喜欢用一种特殊的语言在机器人系统中实现发布,这确实允许使用带有连接/断开连接/发送和接收命令的套接字到给定的地址和端口。因此,我尝试让它在 c# 中工作以采用机器人语言。
在这里您可以找到当前代码:
using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace TestSender
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse("127.0.0.1");
System.Net.IPEndPoint remoteEP = new IPEndPoint(ipAdd, 1883);
Console.WriteLine(sock.Connected.ToString());
sock.Connect(remoteEP);
Console.WriteLine(sock.Connected.ToString());
/*
* control flags byte
* 0 ...RETAIN 0/1 -> 0 only PUBLISH
* 1+2 ...QOS 0,1,2 --> 0 only PUBLISH
* 3 ...DUPe 0/1 --> 0 only PUBLISH
*/
/* control messagetype byte 4...7 (4=low)
0 Reserved 0 Forbidden Reserved
1 CONNECT 1 Client to Server Client request to connect to Server
2 CONNACK 2 Server to Client Connect acknowledgment
3 PUBLISH 3 Client to Server
or Server to Client Publish message
4 PUBACK 4 Client to Server
or Server to Client Publish acknowledgment
5 PUBREC 5 Client to Server
or Server to Client Publish received(assured delivery part 1)
6 PUBREL 6 Client to Server
or Server to Client Publish release(assured delivery part 2)
7 PUBCOMP 7 Client to Server
or Server to Client Publish complete(assured delivery part 3)
8 SUBSCRIBE 8 Client to Server Client subscribe request
9 SUBACK 9 Server to Client Subscribe acknowledgment
A UNSUBSCRIBE 10 Client to Server Unsubscribe request
B UNSUBACK 11 Server to Client Unsubscribe acknowledgment
C PINGREQ 12 Client to Server PING request
D PINGRESP 13 Server to Client PING response
E DISCONNECT 14 Client to Server Client is disconnecting
F Reserved 15 Forbidden Reserved
*/
byte bFlagConenct = 0;
byte bFlagPublish = 0; //no dupe, QOS (at most once = 0), no retain
byte bMessageConnect = 1;
byte bMessageDisConnect = 14;
byte bMessagePublish = 3;
byte bMessageHeaderConnect = Convert.ToByte( 16 * bMessageConnect + bFlagConenct); //10h
byte bMessageHeaderPublish = Convert.ToByte(16 * bMessagePublish + bFlagPublish); //30h
byte bMessageHeaderDisconnect= Convert.ToByte(16 * bMessageDisConnect+ bFlagConenct); //E0h
byte[] byAdress = System.Text.Encoding.ASCII.GetBytes(@"demo/Target");
byte[] byData = System.Text.Encoding.ASCII.GetBytes("{OFF}");
int lenAdress = byAdress.Length;
int lenData = byData.Length;
//get short int, unsinged
ushort sLenAdress = Convert.ToUInt16(lenAdress);
ushort sLenAllData = Convert.ToUInt16(lenAdress+lenData+2);
byte[] byLenTopic = BitConverter.GetBytes(sLenAdress); //High-Low
Array.Reverse(byLenTopic); //High-Low swap
//convert 256 based ushort to 128based ushort
ushort sLenMQTT_128Base=0;
if (sLenAllData>128)
{
//2nd byte needed ... add 128*256
sLenMQTT_128Base = Convert.ToUInt16( sLenAllData + 128 * 256);
}
else
{
//only one byte
sLenMQTT_128Base = sLenAllData;
}
byte[] byLenMQTT;
if (sLenMQTT_128Base > 256)
{
byLenMQTT = BitConverter.GetBytes(sLenMQTT_128Base); //High-Low
}
else
{
byte bLenMQTT = Convert.ToByte(sLenMQTT_128Base);
byLenMQTT = new byte[1]; byLenMQTT[0]= bLenMQTT; //High-Low
}
byte[] BytesData_MQTT = new byte[1+byLenMQTT.Length + byLenTopic.Length + byAdress.Length + byData.Length];
//set message
BytesData_MQTT[0]= bMessageHeaderPublish;
//copy 128Base Len
Array.Copy(byLenMQTT, 0, BytesData_MQTT, 1, byLenMQTT.Length);
//copy Len of Topic
Array.Copy(byLenTopic, 0, BytesData_MQTT, 1+ byLenMQTT.Length, byLenTopic.Length);
//copy Topic
Array.Copy(byAdress, 0, BytesData_MQTT, 1 + byLenMQTT.Length + byLenTopic.Length, byAdress.Length);
//copy data
Array.Copy(byData, 0, BytesData_MQTT, 1 + byLenMQTT.Length + byLenTopic.Length + byAdress.Length, byData.Length);
/*
* Paket:
* Byte1: MessageHeader
* Byte2-x: length of message (all data, using 128 Encoding (High Byte first), 1 Byte len<128,2 (or more) Byte if bigger, bit #7 in a Byte indicating that another byte follows)
* Content: 2 Byte: Länge des Topics (H,L, Encoding 256)
* followed by: Topic (UTF8)
* followed by: Values to be send (UTF8)
*/
byte[] BytesCon_MQTT = new byte[12];
//2byte fixed header
BytesCon_MQTT[0] = bMessageHeaderConnect;
BytesCon_MQTT[1] = 10;
//10+byte variable header
BytesCon_MQTT[2] = 0;
BytesCon_MQTT[3] = 4;
BytesCon_MQTT[4] = System.Text.Encoding.ASCII.GetBytes("M")[0];
BytesCon_MQTT[5] = System.Text.Encoding.ASCII.GetBytes("Q")[0];
BytesCon_MQTT[6] = System.Text.Encoding.ASCII.GetBytes("T")[0];
BytesCon_MQTT[7] = System.Text.Encoding.ASCII.GetBytes("T")[0];
BytesCon_MQTT[8] = 4; //protocoll level 0x04
BytesCon_MQTT[9] = 0; //no user, no pw, no retain, no will qos or flag, no clean
BytesCon_MQTT[10] = 0; //HighByte Keep Alive MSB 0=disabled
BytesCon_MQTT[11] = 0; //Low Byte Keep Alive MSB 0=disabled'
byte[] BytesDisCon_MQTT = new byte[2];
BytesDisCon_MQTT[0] = bMessageHeaderDisconnect;
BytesDisCon_MQTT[1] = 0;
byte[] byInbound=new byte[1000];
sock.Send(BytesCon_MQTT);
Thread.Sleep(1);
sock.Receive(byInbound);
sock.Send(BytesData_MQTT);
Thread.Sleep(1);
sock.Receive(byInbound);
sock.Send(BytesDisCon_MQTT);
Thread.Sleep(1);
sock.Receive(byInbound);
Console.WriteLine(sock.Connected.ToString());
sock.Disconnect(false);
sock.Close();
Console.WriteLine(sock.Connected.ToString());
}
}
}
解决方案
您尚未发送完整的连接数据包。
一个连接数据包不仅仅是 2 个字节,它是一个 2 字节的固定报头,后面是可变报头,然后是有效负载。
一个最小的完整连接数据包头是 12 字节长,然后它需要跟有效载荷。
即使您不打算使用现有的 MQTT 客户端库实现,我也建议您阅读一个并将其与规范进行比较。
推荐阅读
- javascript - socket.io 中经过身份验证的房间中的问题
- php - 告诉我为什么我也可以将数组作为对象访问
- windows - 无法登录Window Partner center Dashboard
- backslash - 字符串中的反斜杠给出 ¥ 而不是反斜杠
- typescript-typings - 如何修复此错误 TS2322:类型“元素”不可分配给类型“HTMLLIElement”
- javascript - 在多选下拉列表中,我无法在列表中的空格之后获取所选值
- python-3.x - 损坏的 DAG:没有名为 auth 的模块
- linux - -bash: /usr/local/cpanel/3rdparty/bin/perl: 没有这样的文件或目录 - linux 服务器有点崩溃
- csv - SSIS 读取平面文件标题列
- python - `import directory.module` 和 `import module` 之间的区别