四、MQTT
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,是轻量级基于代理的发布/订阅的消息传输协议,它可以通过很少的代码和带宽和远程设备连接。例如通过卫星和代理连接,通过拨号和医疗保健提供者连接,以及在一些自动化或小型设备上,而且由于小巧,省电,协议开销小和能高效的向一和多个接收者传递信息,故同样适用于称动应用设备上。
使用MQTT连接ActiveMQ使用的是点对点的Topic消息模型,主要设置mqtt协议的头信息。
MqttClient mqttClient = new MqttClient("tcp://0.0.0.0:1883", "deviceId", new MemoryPersistence());①
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);②
options.setKeepAliveInterval(30);③
mqttClient.connect(options);<pre name="code" class="java">mqttClient.publish("VirtualTopic/"+"deviceId", ("hello virtualTopic").getBytes(), 1, false);④
MqttCallbachMsg callback = new MqttCallbachMsg();
mqttClient.setCallback(callback );
public class MqttCallbachMsg implements MqttCallback{
@Override
public void connectionLost(Throwable cause) {
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println(new String(message.getPayload(),"utf-8"));
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
}
①参数A是mqtt的地址端口号;参数B为设备的唯一标示;参数C有MqttDefaultFilePersistence()和MemoryPersistence两种情况。
②false:如果订阅的客户机断线了,那么要保存其要推送的消息,如果其重新连接时,则将这些消息推送;
true:1表示消除,表示客户机是第一次连接,消息所以以前的连接信息。
③表示响应时间,如果这个时间内,连接或发送操作未完成,则断开tcp连接,表示离线。
④参数A为Topic名称;参数B为message内容;参数C为qos:00表示最多一次 即<=1,01表示至少一次 即>=1,10表示一次,即==1;参数D为是否保持,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它。如果不设那么推送至当前订阅的就释放了。
五、虚拟主题(Virtual Topic)
前面说到,MQTT发过来的消息是Topic模型,但是Topic是广播,所有的监听者都会接收到推送,但是为了保证可用性,通常部署的接收服务器是多个,这样就会导致一个问题:一条消息被处理多次,这显然是我们不想看到的。令人高兴的是,ActiveMQ已经预料到了这种问题:Virtual Topic。顾名思义,它的作用就是把Topic虚拟成Queue,因为Queue的特性是有且只有一个customer。这样可以保证我们的后端处理程序可能可以接收并且只会接受处理一次。
缺省的topic名称为 VirtualTopic. ,第四条说的MQTT的例子就是发送的Virtual Topic请求;Receiver监听的queue名为Consumer.*.VirtualTopic. 。
接收代码:
ActiveMQConnectionFactory factoryA = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, "tcp://101.201.29.101:1889");
Queue queue = new ActiveMQQueue("Consumer.Test.VirtualTopic.*");
ActiveMQConnection conn = (ActiveMQConnection) factoryA.createConnection();
conn.start();
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = session.createConsumer( queue );
MessageListener listener = new MessageListener() {
public void onMessage(Message message) {
try {
//String content = new String(((ActiveMQBytesMessage)message).getMessage().getContent().getData(),"UTF-8");
System.out.println(" => message content:" + message.getJMSDestination().toString());
} catch (Exception e) {
e.printStackTrace();
}
}
};
consumer.setMessageListener(listener);
ActiveMQ是用java写的,并且是spring框架,所有可以称得上是高度灵活。
我们可以通过继承他的接口实现自定义类打成jar包放入lib,最后在activemq.xml中添加插件配置即可
自定义连接验证规则:
public class AuthenticationControlBrokerPlugin implements BrokerPlugin {
private Set userGroup = new HashSet<Object>();
public Broker installPlugin(Broker broker) throws Exception {
return new AuthenticationControlBroker(broker,userGroup);
}
}
public class AuthenticationControlBroker extends BrokerFilter{
private final CopyOnWriteArrayList<SecurityContext> securityContexts = new CopyOnWriteArrayList<SecurityContext>();
private final Set userGroup;
public AuthenticationControlBroker(Broker next,Set userGroup) {
super(next);
this.userGroup = userGroup;
ServiceProxyFactory.init();
}
@Override
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
SecurityContext s = context.getSecurityContext();
try {
if (s == null) {
//TODO:你的自定义规则
userGroup.add(info.getUserName());
s = new SecurityContext(info.getUserName()) {
@Override
public Set<Principal> getPrincipals() {
// TODO Auto-generated method stub
return userGroup;
}
};
context.setSecurityContext(s);
securityContexts.add(s);
}
super.addConnection(context, info);
} catch (Exception e) {
securityContexts.remove(s);
context.setSecurityContext(null);
throw e;
}
}
}
配置文件:
<plugins><bean xmlns="http://www.springframework.org/schema/beans"
id="myPlugin" class="你的class路径"></bean></plugins>
后记:目前用到和想到的就这些了,有空再仔细看一下相关知识,放到下篇中