MQTT手写协议

一、连接

 

Wireshark抓包工具

socket.Connect("127.0.0.1", 10613);//连接WLAN

socket.Connect("127.0.0.1", 1883);//连接自己的桌面应用程序 Adapter for loopback

 

 

连接成功

 

 

换一个协议版本0x06

都没有响应,直接被踢了, 没有返回错误信息,不支持的协议版本

端口过滤 tcp.port==1883

 

如果不返回固定头部32就不是响应报文

这样判断,这个库不太行

 

用户名密码还是有判断的

协议版本没有处理响应

 

二、订阅

//订阅主题多个,用逗号分隔,支持中文
List<string> topic = new List<string>
{
"车间/设备","zys"
};
Subscription(topic);

 

 有几个topic,再加上4个字节,就是最终响应的字节数

 

三、心跳

死循环,要异步处理,新线程处理

100秒,稍微等个90秒

 区别就是请求类型,请求12,响应13

 

// See https://aka.ms/new-console-template for more information
using System.Net.Sockets;
using System.Text;

class Program
{
    static Socket socket;

    static void Main(string[] args)
    {
        Console.WriteLine("Hello, World!");
        Connection();
        //订阅主题多个,用逗号分隔,支持中文
        List<string> topic = new List<string>
            {
                "车间/设备","zys"
            };
        Subscription(topic);
        Console.ReadKey();
    }
    static void Connection()
    {
        //MQTT不支持udp
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//Socket支持UDP
        socket.Connect("127.0.0.1", 1883);
        List<byte> headBytes = new List<byte>()
        {
            1<<4//连接请求消息类型
        };
        string protocolName = "MQTT";
        byte[] protocolNameBytes = Encoding.UTF8.GetBytes(protocolName);//协议名称,固定为MQTT,对应服务端,UTF8和ASCII编码对英文字母来说都可以,英文字母占1个字节,中文占2个字节 英文字母是最低支持,汉字ASCII是没有的,不可以使用UTF8Encoding


        //大小端,高位放在低字节
        List<byte> bodyBytes = new List<byte>();
        bodyBytes.Add((byte)(protocolNameBytes.Length / 256 % 256));
        bodyBytes.Add((byte)(protocolNameBytes.Length % 256));
        bodyBytes.AddRange(protocolNameBytes);
        bodyBytes.Add(0x04);//协议级别,固定为4,对应MQTT 3.1.1

        //QaS
        byte flagByte = 0;
        //用户名
        flagByte |= 128; //1000 0000  128
        //密码           //0100 0000  64
        flagByte |= 64;  //1100 0000  变成

        //CleanSession  //0000 0010  2
        flagByte |= 2;   //1100 0010  变成
        bodyBytes.Add(flagByte);

        int seconds = 100;//保持连接时间,单位秒,最大65535,对应MQTT 3.1.1
        bodyBytes.Add((byte)(seconds / 256 % 256));
        bodyBytes.Add((byte)(seconds % 256));


        //客户端ID
        string clientId = "Z001";
        byte[] clientIdBytes = Encoding.UTF8.GetBytes(clientId);
        bodyBytes.Add((byte)(clientIdBytes.Length / 256 % 256));
        bodyBytes.Add((byte)(clientIdBytes.Length % 256));
        bodyBytes.AddRange(clientIdBytes);

        //用户名
        string userName = "admin";
        byte[] userNameBytes = Encoding.UTF8.GetBytes(userName);
        bodyBytes.Add((byte)(userNameBytes.Length / 256 % 256));
        bodyBytes.Add((byte)(userNameBytes.Length % 256));
        bodyBytes.AddRange(userNameBytes);

        //密码
        string password = "123456";// apolo默认密码:password
        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
        bodyBytes.Add((byte)(passwordBytes.Length / 256 % 256));
        bodyBytes.Add((byte)(passwordBytes.Length % 256));
        bodyBytes.AddRange(passwordBytes);

        headBytes.Add((byte)bodyBytes.Count);
        headBytes.AddRange(bodyBytes);
        socket.Send(headBytes.ToArray());

        byte[] respBytes = new byte[4];
        int recvLen = socket.Receive(respBytes, 0, 4, SocketFlags.None);
        string respStr = Encoding.UTF8.GetString(respBytes, 0, recvLen);
        Console.WriteLine(respStr);

        //判断是否连接正常
        //开始心跳
        Task.Run(async () =>
        {
            byte[] pingBytes = new byte[2] { 12 << 4, 0 };
            while (true)
            {
                await Task.Delay(10000);
                socket.Send(pingBytes);
            }
        });
    }

    static Random random = new Random();
    static void Subscription(List<string> topics)
    {
        List<byte> headerBytes = new List<byte>();
        byte msgType = 8 << 4;   //  1000 0000
        headerBytes.Add((byte)(msgType | 2));



        List<byte> bodyBytes = new List<byte>();
        int pi = random.Next(0, 1000);  // Package Identifier
        bodyBytes.Add((byte)(pi / 256 % 256));
        bodyBytes.Add((byte)(pi % 256));


        foreach (var item in topics)
        {
            byte[] itemBytes = Encoding.UTF8.GetBytes(item);
            bodyBytes.Add((byte)(itemBytes.Length / 256 % 256));
            bodyBytes.Add((byte)(itemBytes.Length % 256));
            bodyBytes.AddRange(itemBytes);

            bodyBytes.Add(0x00); // QoS 0
        }

        headerBytes.Add((byte)bodyBytes.Count);
        headerBytes.AddRange(bodyBytes);

        socket.Send(headerBytes.ToArray());
    }
}     
View Code

 

posted on 2025-03-01 16:30  张彦山  阅读(30)  评论(0)    收藏  举报