flink接入mqtt数据源

flink没有原生的mqtt数据源,但可以通过自定义数据源进行添加mqtt的数据源。

java 复制代码
package com.agioe.flink.source.mqtt;
 
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.eclipse.paho.mqttv5.client.*;
import org.eclipse.paho.mqttv5.client.persist.MemoryPersistence;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.eclipse.paho.mqttv5.common.packet.MqttProperties;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

 
public class MqttSource extends RichSourceFunction<String> {
    //存储服务
    private static MqttClient client;
    //存储订阅主题
    private static MqttTopic mqttTopic;
    //阻塞队列存储订阅的消息
    private BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

    private StartupParams startupParams;

    public MqttSource(StartupParams startupParams) {
        this.startupParams = startupParams;
    }

    //包装连接的方法
    private void connect() throws MqttException {
        String username = startupParams.pro.getProperty("mqtt.username");
        String password = startupParams.pro.getProperty("mqtt.password");


        //配置连接参数
        MqttConfig mqttConfigBean = new MqttConfig(null, null, "tcp://192.168.15.13:1883", "mqtt-client", "testtopic/#");
        //连接mqtt服务器
        client = new MqttClient(mqttConfigBean.getHostUrl(), mqttConfigBean.getClientId(), new MemoryPersistence());
        MqttConnectionOptions options = new MqttConnectionOptions();

        options.setUserName(mqttConfigBean.getUsername());
        options.setPassword(mqttConfigBean.getPassword() == null ? null : mqttConfigBean.getPassword().getBytes(StandardCharsets.UTF_8));
//        options.setCleanSession(false);   //是否清除session
//        options.setSessionExpiryInterval();
        // 设置超时时间
        options.setConnectionTimeout(30);
        // 设置会话心跳时间
        options.setKeepAliveInterval(20);
        try {
            String[] msgtopic = mqttConfigBean.getMsgTopic();
            //订阅消息
            int[] qos = new int[msgtopic.length];
            for (int i = 0; i < msgtopic.length; i++) {
                qos[i] = 0;
            }
            client.setCallback(new MsgCallback(client, options, msgtopic, qos) {
            });
            client.connect(options);
            client.subscribe(msgtopic, qos);
            System.out.println("MQTT连接成功:" + mqttConfigBean.getClientId() + ":" + client);
        } catch (Exception e) {
            System.out.println("MQTT连接异常:" + e);
        }
    }

    //实现MqttCallback,内部函数可回调
    class MsgCallback implements MqttCallback {
        private MqttClient client;
        private MqttConnectionOptions options;
        private String[] topic;
        private int[] qos;

        public MsgCallback() {
        }

        public MsgCallback(MqttClient client, MqttConnectionOptions options, String[] topic, int[] qos) {
            this.client = client;
            this.options = options;
            this.topic = topic;
            this.qos = qos;
        }

        //连接失败回调该函数
        @Override
        public void disconnected(MqttDisconnectResponse mqttDisconnectResponse) {
            System.out.println("MQTT连接断开,发起重连");
            while (true) {
                try {
                    Thread.sleep(1000);
                    client.connect(options);
                    //订阅消息
                    client.subscribe(topic, qos);
                    System.out.println("MQTT重新连接成功:" + client);
                    break;
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }

        @Override
        public void mqttErrorOccurred(MqttException e) {

        }

        //收到消息回调该函数
        @Override
        public void messageArrived(String s, MqttMessage message) throws Exception {
            System.out.println();
            //订阅消息字符
            String msg = new String(message.getPayload());
            byte[] bymsg = getBytesFromObject(msg);
            System.out.println("topic:" + topic);
            queue.put(msg);

        }

        @Override
        public void deliveryComplete(IMqttToken iMqttToken) {
        }

        @Override
        public void connectComplete(boolean b, String s) {
            System.out.println("MQTT重新连接成功:" + client);
        }

        @Override
        public void authPacketArrived(int i, MqttProperties mqttProperties) {

        }

        //对象转化为字节码
        public byte[] getBytesFromObject(Serializable obj) throws Exception {
            if (obj == null) {
                return null;
            }
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(obj);
            return bo.toByteArray();
        }
    }

    //flink线程启动函数
    @Override
    public void run(final SourceContext<String> ctx) throws Exception {
        connect();
        //利用死循环使得程序一直监控主题是否有新消息
        while (true) {
            //使用阻塞队列的好处是队列空的时候程序会一直阻塞到这里不会浪费CPU资源
            ctx.collect(queue.take());
        }
    }


    @Override
    public void cancel() {

    }

    /**
     * 订阅某个主题
     *
     * @param topic
     * @param qos
     */
    public void subscribe(String topic, int qos) {
        try {
            System.out.println("topic:" + topic);
            client.subscribe(topic, qos);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    public MqttClient getClient() {
        return client;
    }

    public void setClient(MqttClient client) {
        this.client = client;
    }

    public MqttTopic getMqttTopic() {
        return mqttTopic;
    }

    public void setMqttTopic(MqttTopic mqttTopic) {
        this.mqttTopic = mqttTopic;
    }


}
复制代码
public class MqttConfig implements Serializable {

    public MqttConfig(String username, String password, String hostUrl, String clientId, String msgTopic) {
        this.username = username;
        this.password = password;
        this.hostUrl = hostUrl;
        this.clientId = clientId;
        this.msgTopic = msgTopic;
    }
    //连接名称
    private String username;
    //连接密码
    private String password;
    //ip地址以及端口号
    private String hostUrl;
    //服务器ID注意不能与其他连接重复,否则会连接失败
    private String clientId;
    //订阅的主题
    private String msgTopic;


    //获得用户名
    public String getUsername() {
        return username;
    }
    //获得密码
    public String getPassword() {
        return password;
    }
    //获得客户端id
    public String getClientId() {
        return clientId;
    }
    //获得服务端url
    public String getHostUrl() {
        return hostUrl;
    }
    //获得订阅
    public String[] getMsgTopic() {
        String[] topic = msgTopic.split(",");
        return topic;
    }

}

在flink的main函数中增加

复制代码
    stream = env.addSource(new MqttSource(StartupParams.instance));
相关推荐
tcoding1 天前
《基于Apache Flink的流处理》笔记
笔记·flink·apache
linmoo19861 天前
Flink 系列之二十二 - 高级概念 - 保存点
大数据·flink·savepoint·保存点
Doker 多克2 天前
Flink CDC —部署模式
大数据·flink
酷爱码2 天前
Spring Boot 整合 Apache Flink 的详细过程
spring boot·flink·apache
问道飞鱼2 天前
Flink 高可用集群部署指南
flink·部署·批处理·流式批处理
渣渣盟3 天前
基于Scala实现Flink的三种基本时间窗口操作
开发语言·flink·scala
网安INF3 天前
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
java·web安全·网络安全·flink·漏洞
一叶知秋哈3 天前
Java应用Flink CDC监听MySQL数据变动内容输出到控制台
java·mysql·flink
代码匠心3 天前
从零开始学Flink:揭开实时计算的神秘面纱
java·大数据·后端·flink