Centos安装emq及插件的使用、java版mqtt构建客户端和服务端

emq官网插件地址 http://emqtt.com/docs/v2/plugins.html#

官方文档   https://docs.emqx.io/broker/v3/cn/

由于emqttd是用Erlang语言编写的,所以,在Linux下安装时,需要先安装Erlang
yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel

下载地址: http://emqtt.com/downloads

程序包下载后,可直接解压启动运行,例如 Mac 平台:

unzip emqttd-macosx-v2.0.zip && cd emqttd

禁用匿名认证
修改etc目录下的emq.conf文件, vim emq.conf 找到 mqtt.all_anonymous配置项将其置为false


建库建表
配置数据库
 etc/plugins/emq_auth_mysql.conf 配置 ‘super_query’, ‘auth_query’, ‘password_hash’:
EMQ 消息服务器默认访问控制,在 etc/emq.conf 中设置:
## ACL nomatch
mqtt.acl_nomatch = allow
 
## Default ACL File
mqtt.acl_file = etc/acl.conf

# 启动emqttd
./bin/emqttd start

# 检查运行状态
./bin/emqttd_ctl status

# 停止emqttd
./bin/emqttd stop

/sbin/iptables -I INPUT -p tcp --dport 18083 -j ACCEPT
/sbin/iptables -I INPUT -p tcp --dport 1883 -j ACCEPT
/sbin/iptables -I INPUT -p tcp --dport 8083 -j ACCEPT


web页面管理端插件设置emq_dashboard.conf

emq_auth_mysql: MySQL 认证/访问控制插件?
MySQL 认证/访问控制插件,基于 MySQL 库表认证鉴权: https://github.com/emqtt/emq-auth-mysql

MQTT 用户表
CREATE TABLE `mqtt_user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  `salt` varchar(35) DEFAULT NULL,
  `is_superuser` tinyint(1) DEFAULT 0,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `mqtt_username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
注解

MySQL 插件可使用系统自有的用户表,通过 ‘authquery’ 配置查询语句。
MQTT 访问控制表
CREATE TABLE `mqtt_acl` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `allow` int(1) DEFAULT NULL COMMENT '0: deny, 1: allow',
  `ipaddr` varchar(60) DEFAULT NULL COMMENT 'IpAddress',
  `username` varchar(100) DEFAULT NULL COMMENT 'Username',
  `clientid` varchar(100) DEFAULT NULL COMMENT 'ClientId',
  `access` int(2) NOT NULL COMMENT '1: subscribe, 2: publish, 3: pubsub',
  `topic` varchar(100) NOT NULL DEFAULT '' COMMENT 'Topic Filter',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `mqtt_acl` (`id`, `allow`, `ipaddr`, `username`, `clientid`, `access`, `topic`)
VALUES
    (1,1,NULL,'$all',NULL,2,'#'),
    (2,0,NULL,'$all',NULL,1,'$SYS/#'),
    (3,0,NULL,'$all',NULL,1,'eq #'),
    (5,1,'127.0.0.1',NULL,NULL,2,'$SYS/#'),
    (6,1,'127.0.0.1',NULL,NULL,2,'#'),
    (7,1,NULL,'dashboard',NULL,1,'$SYS/#');
配置 MySQL 认证鉴权插件
etc/plugins/emq_auth_mysql.conf:

## Mysql Server
auth.mysql.server = 127.0.0.1:3306

## Mysql Pool Size
auth.mysql.pool = 8

## Mysql Username
## auth.mysql.username =

## Mysql Password
## auth.mysql.password =

## Mysql Database
auth.mysql.database = mqtt

## Variables: %u = username, %c = clientid

## Authentication Query: select password only
auth.mysql.auth_query = select password from mqtt_user where username = '%u' limit 1

## Password hash: plain, md5, sha, sha256, pbkdf2
auth.mysql.password_hash = sha256

## %% Superuser Query
auth.mysql.super_query = select is_superuser from mqtt_user where username = '%u' limit 1

## ACL Query Command
auth.mysql.acl_query = select allow, ipaddr, username, clientid, access, topic from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'
加载 MySQL 认证鉴权插件
./bin/emqttd_ctl plugins load emq_auth_mysql


emq_auth_username - 用户名密码认证插件?
EMQ 2.0-rc.2 版本将用户名认证模块改为独立插件: https://github.com/emqtt/emq_auth_username

用户名认证配置
etc/plugins/emq_auth_username.conf:

##auth.user.$N.username = admin
##auth.user.$N.password = public

## Examples:
##auth.user.1.username = admin
##auth.user.1.password = public
##auth.user.2.username = feng@emqtt.io
##auth.user.2.password = public
两种方式添加用户:

直接在 etc/plugins/emq_auth_username.conf 中明文配置默认用户例如:

auth.username.test = public
通过 ‘./bin/emqttd_ctl’ 管理命令行添加用户:

$ ./bin/emqttd_ctl users add <Username> <Password>
加载用户名认证插件
./bin/emqttd_ctl plugins load emq_auth_username


emq_web_hook    Web Hook 插件
在web管理页面emq_web_hook配置一个可以访问的地址(java测试代码如下)
打断点观察(有客户端连接时会请求到管理端配置的地址)

import com.aisino.domain.SystemConfig;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@javax.servlet.annotation.WebServlet("/zjx.do")
public class WebServlet extends HttpServlet {
    private static final Logger logger = LogManager.getLogger(WebServlet.class);

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding(SystemConfig.CHARSET);
        response.setCharacterEncoding(SystemConfig.CHARSET);
        response.setContentType("application/json");
        ServletInputStream inputStream = request.getInputStream();
        String requestXML = IOUtils.toString(inputStream,SystemConfig.CHARSET);
        JSONObject jsonObject = JSON.parseObject(requestXML);
        String active = jsonObject.getString("action");
        String client_id = jsonObject.getString("client_id");
        logger.info(active + client_id);
        logger.info(requestXML);
        IOUtils.closeQuietly(inputStream);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // req.setCharacterEncoding(SystemConfig.CHARSET);
        request.setCharacterEncoding(SystemConfig.CHARSET);
        response.setCharacterEncoding(SystemConfig.CHARSET);
        response.setContentType("application/json");

        // 定义返回的Json
        // String reponse = StringUtils.EMPTY;
        String responseXML = StringUtils.EMPTY;
        final PrintWriter out = response.getWriter();
        try {
            // 业务处理方法
            logger.info(responseXML);
        } catch (Exception e) {
            logger.error("--线程(ID:" + Thread.currentThread().getId() + ")系统异常:{}", e);
        } finally {
            // 向请求端发回反馈信息
            out.print(responseXML);
            out.flush();
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}

 

我这里有优化过的emq包(链接:https://pan.baidu.com/s/1jAze5JFeeQ7ltAVBfQOB-A 提取码:baph ),

直接解压,修改emqttd/etc/emq.conf 里参数:node.name就可以使用 

 

管理端地址http://127.0.0.1:18083(默认用户名密码admin public)

emq提供的接口需要的可以使用,其他的自己学习。

服务端代码:

public class Server {
    public static final String HOST = "tcp://192.168.103.1:1883";
    public static final String TOPIC = "THIS/IS/TOPIC/ID/0";
    private static final String clientid = "ID-0";
    private MqttClient client;
    private MqttTopic topic;
    private String userName = "admin";
    private String passWord = "public";

    private MqttMessage message;
    
    private String getMessage() throws Exception{
        String reqJson = 
        		"{"+
	            "'GHR':'zhangsan',"+
	            "'SHR':'lisi',"+
                "'}";
       return reqJson;
    	
    }

    public Server() throws MqttException {
        client = new MqttClient(HOST, clientid, new MemoryPersistence());
        connect();
    }

    private void connect() {
        MqttConnectOptions options = new MqttConnectOptions();
        options.setCleanSession(false);
        options.setUserName(userName);
        options.setPassword(passWord.toCharArray());
        options.setConnectionTimeout(200);
        options.setKeepAliveInterval(20);
        try {
            client.setCallback(new PushCallback());
            client.connect(options);
            topic = client.getTopic(TOPIC);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void publish(MqttTopic topic , MqttMessage message) throws MqttPersistenceException,
            MqttException {
        MqttDeliveryToken token = topic.publish(message);
        token.waitForCompletion();
        System.out.println("message is published completely! "
                + token.isComplete());
    }

    public static void main(String[] args) throws Exception {
        Server server = new Server();
        server.message = new MqttMessage();
        server.message.setQos(1);
        server.message.setRetained(true);
        server.message.setPayload(server.getMessage().getBytes());
        server.publish(server.topic , server.message);
        System.out.println(server.message.isRetained() + "------ratained");
    }
}

客户端代码

public class Client {
    public static final String TOPIC = "THIS/IS/TOPIC/ID/0";
    private static final String clientid = SystemConfig.CLIENTID;  
    private MqttClient client;  
    private MqttConnectOptions options;  
    private String userName = "admin";
    private String passWord = "public";
  
    private void start() {  
        try {  
            client = new MqttClient(HOST, clientid, new MemoryPersistence());  
            options = new MqttConnectOptions();  
            options.setCleanSession(true);  
            options.setUserName(userName);  
            options.setPassword(passWord.toCharArray());  
            options.setConnectionTimeout(10000000);
            options.setKeepAliveInterval(60000000);
            client.setCallback(new PushCallback());  
            MqttTopic topic = client.getTopic(TOPIC);   
            client.connect(options);  
            int[] Qos  = {1};  
            String[] topic1 = {TOPIC};  
            client.subscribe(topic1, Qos);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
   
    public static void main(String[] args) throws MqttException {
    	new Thread(
    			new Runnable() {
    				@Override
    				public void run() {
    					JOptionPane.showMessageDialog( null,"D1设备启动.......");
    				}
    			}).start();
    	Client client = new Client();
        client.start();
    }
}

回调函数:

public class PushCallback implements MqttCallback {  
    int i= 0;
    private static final Logger logger = LogManager.getLogger(PushCallback.class);
    private final HandlerRequest handlerRequest = new HandlerRequest();
    public void connectionLost(Throwable cause) {  
		logger.info("--线程(ID:" + Thread.currentThread().getId() + "),连接丢失了");
        System.out.println("连接缺失"+cause);  
    }  
    
    public void deliveryComplete(IMqttDeliveryToken token) {
        try {
			System.out.println("deliveryComplete---------" + token.isComplete()+"mqtt"+token.getMessage());
		} catch (MqttException e) {
			e.printStackTrace();
		}  
    }

    public void messageArrived(String topic, MqttMessage message) throws Exception {
		if(topic.endsWith("disconnected")){
			logger.info("--线程(ID:" + Thread.currentThread().getId()+").设备离线,离线原因为:"+message.toString());
		}else if(topic.endsWith("connected")){
                logger.info("--线程(ID:" + Thread.currentThread().getId()+"). 设备上线,连接信息:"+message.toString());
		}
        System.out.println("订阅到的主题 : " + topic);  
        System.out.println("发送等级 : " + message.getQos());  
        System.out.println("发送的消息 : " + new String(message.getPayload()));  
        System.out.println("源消息"+message);
    }
}

我用的依赖:

<!-- MQTT client -->
        <dependency>
            <groupId>org.eclipse.paho</groupId>
            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
            <version>1.1.0</version>
        </dependency>

效果:

服务端

客户端:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值