问题
my previous research on Google led me to this page:https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html here I found some informations … and I startet trying. The testing setup is against a local mosquito. This works so far (it runs without errors), but if I send the PUBLISH message, I get disconnected from mosquito.
[edit] So the big Question is, what's wrong with the message.
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
You may wonder WHY THE HELL I'm trying to hardcode the implementation … it is to understand the functionality. I like to implement the Publishing in a robot system with a special language, which does allow the use of socket with connect / disconneect / send and receive commands to a given adress and port. Therefore I try to get it working in c# to adopt to the robot language.
Here you find the current code:
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());
}
}
}
回答1:
You have not sent a complete connect packet.
A connect packet is not just 2 bytes, it's a 2 byte fixed header, followed by the variable header and then a payload.
A minimal full connect packet header is 12bytes long, then it needs to be followed by the payload.
Even if you are not planning to use an existing MQTT Client library implementation I would suggest you read one and compare it to the spec.
来源:https://stackoverflow.com/questions/65088631/creating-a-thin-mqtt-publisher-without-using-a-stack-how-to