Creating a thin MQTT publisher without using a stack (How To)

一曲冷凌霜 提交于 2021-01-29 02:09:13

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!