Emq源码分析:Emq端到端的问题

文章目录


ps:工作需要,不是专门分析emq源码的,随便看看,勿喷~

目前看emq是不能够端到端的

emq的消息发送函数有两个参数

public void sendNoWait(MqttWireMessage message, MqttToken token) throws MqttException {
	。。。。
}

通过打断点发现这个token只有是校验或者心跳类的send请求的时候才有
Emq源码分析:Emq端到端的问题_第1张图片
而只有这个东西里面才有hashtable

再看消费端
CommsTokenStore这个类
简单看下注释:

/**
 * Provides a "token" based system for storing and tracking actions across 
 * multiple threads. 
 * When a message is sent, a token is associated with the message
 * and saved using the {@link #saveToken(MqttToken, MqttWireMessage)} method. Anyone interested
 * in tacking the state can call one of the wait methods on the token or using 
 * the asynchronous listener callback method on the operation. 
 * The {@link CommsReceiver} class, on another thread, reads responses back from 
 * the network. It uses the response to find the relevant token, which it can then 
 * notify. 
 * 
 * Note:
 *   Ping, connect and disconnect do not have a unique message id as
 *   only one outstanding request of each type is allowed to be outstanding
 */
public class CommsTokenStore {

}

/ **
*提供基于“令牌”的系统,用于存储和跟踪操作
*多线程。
*发送消息时,令牌与消息关联
*并使用{@link #saveToken(MqttToken,MqttWireMessage)}方法保存。有兴趣的人
*在处理状态时可以调用令牌上的其中一个等待方法或使用
*关于操作的异步监听器回调方法。
*另一个线程上的{@link CommsReceiver}类从中读取响应

  • 网络。它使用响应来查找相关的令牌,然后它可以
    *通知。
  • 注意:
  • Ping,connect和disconnect没有唯一的消息ID
    *每种类型中只有一项未完成的请求是允许的
  • /

意思就是说每次发送消息(包括校验和心跳)都有一个与之对应的token,将message的id作为了token的id

但是我们接着看CommsReceiver
看一下他的run方法

public void run() {
		final String methodName = "run";
		MqttToken token = null;
		
		while (running && (in != null)) {
			try {
				//@TRACE 852=network read message
				log.fine(CLASS_NAME,methodName,"852");
				receiving = in.available() > 0;
				MqttWireMessage message = in.readMqttWireMessage();
				receiving = false;
				
				if (message instanceof MqttAck) {
					token = tokenStore.getToken(message);
					if (token!=null) {
						synchronized (token) {
							// Ensure the notify processing is done under a lock on the token
							// This ensures that the send processing can complete  before the 
							// receive processing starts! ( request and ack and ack processing
							// can occur before request processing is complete if not!
							clientState.notifyReceivedAck((MqttAck)message);
						}
					} else {
						// It its an ack and there is no token then something is not right.
						// An ack should always have a token assoicated with it.
						throw new MqttException(MqttException.REASON_CODE_UNEXPECTED_ERROR);
					}
				} else {
					// A new message has arrived
					clientState.notifyReceivedMsg(message);
				}
			}

...
}

可以看到 clientState.notifyReceivedAck((MqttAck)message); 这个方法,将message转为了ack,然后进去,

protected void notifyReceivedAck(MqttAck ack) throws MqttException {
		...
		MqttToken token = tokenStore.getToken(ack);
		...
		}

有根据key得到token的操作

而当token不是ack的时候

clientState.notifyReceivedMsg(message);

这个方法中并没有根据key得到token的操作,获取token也是没有意义的

包括从consumer的messageArrived方法往里面跟(其实这个操作就是重写里hanleMessage里面的一些东西而已),跟到了CommsCallback的run方法

public void run() {
		final String methodName = "run";
		while (running) {
			try {
				// If no work is currently available, then wait until there is some...
				try {
					synchronized (workAvailable) {
						if (running && messageQueue.isEmpty()
								&& completeQueue.isEmpty()) {
							// @TRACE 704=wait for workAvailable
							log.fine(CLASS_NAME, methodName, "704");
							workAvailable.wait();
						}
					}
				} catch (InterruptedException e) {
				}

				if (running) {
					// Check for deliveryComplete callbacks...
					MqttToken token = null;
					synchronized (completeQueue) {
					    if (!completeQueue.isEmpty()) {
						    // First call the delivery arrived callback if needed
						    token = (MqttToken) completeQueue.elementAt(0);
						    completeQueue.removeElementAt(0);
					    }
					}
					if (null != token) {
						handleActionComplete(token);
					}
					
					// Check for messageArrived callbacks...
					MqttPublish message = null;
					synchronized (messageQueue) {
					    if (!messageQueue.isEmpty()) {
						    // Note, there is a window on connect where a publish
						    // could arrive before we've
						    // finished the connect logic.
							message = (MqttPublish) messageQueue.elementAt(0);

							messageQueue.removeElementAt(0);
					    }
					}
					if (null != message) {
						handleMessage(message);
					}
				}

				if (quiescing) {
					clientState.checkQuiesceLock();
				}

...
}

可以看到从两个queue中获取token和message
Emq源码分析:Emq端到端的问题_第2张图片
completequeue是0

以上token在这里只是一个校验的操作,只在首次连接、心跳等操作的时候有作用,发送普通消息的时候虽然也会发送token,但是没有实际的作用,所以我们不能通过agent技术做一些端到端。

你可能感兴趣的:(#,MQ,------,EMq)