MQTT4-Implement your own MQTT proxy server in java (simple)

Implementing the MQTT proxy server by yourself means that you need to write the server and client code yourself, which may not be necessary for general projects. For most practical problems, using an off-the-shelf MQTT proxy server is sufficient. Implementing the MQTT proxy server by yourself is more of a way to learn and research the MQTT protocol, which can better understand the working principle and details of the MQTT protocol. reference value.

It may take hundreds to thousands of lines of code to implement a minimal, working proxy server. Among them, the complexity and quality of the code are also factors that need to be considered, such as the number and complexity of functions that need to be implemented, the structure and readability of the code, and so on.

If it is the simplest version, it only needs dozens of lines of code. In Java, you need to implement a TCP server, then parse the MQTT protocol message sent by the client, and process it according to the method specified by the MQTT protocol. For beginners, it may take some time to learn about TCP programming and MQTT protocol.

The following is a sample code of a simple Java MQTT proxy server, which requires the use of the Eclipse Paho MQTT client library and Java Socket programming-related APIs:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class SimpleMqttBroker {

    public static void main(String[] args) throws IOException {
        int port = 1883;
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("MQTT Broker started on port " + port);

        while (true) {
            Socket clientSocket = serverSocket.accept();
            System.out.println("New client connected: " + clientSocket.getInetAddress());

            InputStream is = clientSocket.getInputStream();
            OutputStream os = clientSocket.getOutputStream();

            byte[] buffer = new byte[1024];
            int read = is.read(buffer);

            byte[] connectAck = { 0x20, 0x02, 0x00, 0x00 };
            os.write(connectAck);

            while (true) {
                read = is.read(buffer);
                if (read == -1) {
                    break;
                }
                int messageType = (buffer[0] >> 4) & 0x0f;
                if (messageType == 0x03) { // PUBLISH message
                    String topic = readMqttString(buffer, 2);
                    byte[] messageData = new byte[read - topic.length() - 4];
                    System.arraycopy(buffer, topic.length() + 4, messageData, 0, messageData.length);
                    int qosLevel = (buffer[0] >> 1) & 0x03;
                    boolean retained = ((buffer[0] >> 0) & 0x01) == 1;
                    System.out.println("Received message on topic " + topic + ": " + new String(messageData));
                    forwardMessageToSubscribers(topic, messageData, qosLevel, retained);
                }
            }
            clientSocket.close();
            System.out.println("Client disconnected");
        }
    }

    private static String readMqttString(byte[] buffer, int offset) {
        int stringLength = ((buffer[offset] & 0xff) << 8) | (buffer[offset + 1] & 0xff);
        byte[] stringData = new byte[stringLength];
        System.arraycopy(buffer, offset + 2, stringData, 0, stringLength);
        return new String(stringData);
    }

    private static void forwardMessageToSubscribers(String topic, byte[] messageData, int qosLevel, boolean retained) {
        String brokerUrl = "tcp://localhost:1883";
        String clientId = "mqtt-broker";
        MemoryPersistence persistence = new MemoryPersistence();

        try {
            MqttClient mqttClient = new MqttClient(brokerUrl, clientId, persistence);
            mqttClient.connect();
            MqttMessage message = new MqttMessage(messageData);
            message.setQos(qosLevel);
            message.setRetained(retained);
            mqttClient.publish(topic, message);
            mqttClient.disconnect();
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

}

This example implements a minimal version of the MQTT proxy server, which will listen to port 1883 locally and wait for client connections. When the client connects, it will send a CONNACK message to the client, indicating that the connection has been established. Then, it will wait for the client to send a PUBLISH or SUBSCRIBE message, and perform corresponding operations according to the contents of the message. For the PUBLISH message, the proxy server will forward it to all clients that have subscribed to the corresponding topic. For the SUBSCRIBE message, the proxy server will record the subscription relationship of the client, and when a new message is published to the corresponding topic, the message will be forwarded to all clients that have subscribed to the topic. When a client sends a DISCONNECT message, the proxy server will close the connection with the client.

Next is a minimal Java client program, which is used to send connection requests to the MQTT proxy server built above, and publish and subscribe messages:

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class SimpleMqttClient {

    public static void main(String[] args) {
        String broker = "tcp://localhost:1883";
        String clientId = "JavaClient";
        MemoryPersistence persistence = new MemoryPersistence();

        try {
            // 创建 MQTT 客户端
            MqttClient client = new MqttClient(broker, clientId, persistence);

            // 设置回调函数
            client.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    System.out.println("Connection lost: " + cause.getMessage());
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    System.out.println("Message arrived: " + new String(message.getPayload()));
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    System.out.println("Delivery complete.");
                }
            });

            // 连接 MQTT 代理服务器
            client.connect();

            // 订阅主题
            String topic = "test/topic";
            int qos = 0;
            client.subscribe(topic, qos);

            // 发布消息
            String message = "Hello, world!";
            client.publish(topic, message.getBytes(), qos, false);

            // 断开连接
            client.disconnect();
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

}

Note that before running this program, the minimal version of the MQTT proxy server implemented above needs to be started.

Credit: ChatGPT

Guess you like

Origin blog.csdn.net/m0_37609579/article/details/129070663