Mina伪装接收到心跳回复

在应用中,作为客户端,可能会遇到服务端不回复心跳的情况,那么这个时候就需要客户端自发自收。

不必费力写一个定时器向自身发送心跳回复,直接在发送时调用其内部API就可以:

public class KeepAliveGatewayZigbee implements KeepAliveMessageFactory {

	public static final String ROBOT_HEART = "robot_heart";
	public static final String GATEWAY_HEART = "gateway_heart";

	@Override
	public boolean isRequest(IoSession ioSession, Object o) {
		if (o instanceof String) {
            String msg = (String) o;
			if (ROBOT_HEART.equalsIgnoreCase(msg)) {
                L.v("发送心跳");
				//假装收到心跳
                ioSession.getFilterChain().fireMessageReceived(GATEWAY_HEART);
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean isResponse(IoSession ioSession, Object o) {
		if (o instanceof String) {
            String msg = (String) o;
			if (GATEWAY_HEART.equalsIgnoreCase(msg)) {
                L.v("接收心跳");
				return true;
			}
		}
		return false;
	}

	@Override
	public Object getRequest(IoSession ioSession) {
		return ROBOT_HEART;
	}

	@Override
	public Object getResponse(IoSession ioSession, Object o) {
		return o;
	}
}

是的,只需要在判断为发送心跳的isRequest方法中,调用一次fireMessageReceived传入应该回复的心跳即可。

究其原理,是因为我们清楚整个消息传递是怎样的。
这个可以从Mina源码看心跳超时机制略知一二,如同心跳超时调用sessionIdle一样,消息传递会回调一系列类似于sessionIdle的方法。

当我们实现心跳机制时,肯定都会使用类似

getFilterChain().addLast(HEARTBEAT, keepAliveFilter)

的代码添加一个KeepAliveFilter,KeepAliveFilter继承自IoFilterAdapter。
当这个Filter被添加到FilterChain中时,每次session的动作都会触发其相应的方法。而KeepAliveFilter正是对这些方法进行了覆写,实现了一些判断的逻辑。

比如每次发送消息后与接收消息后:

//KeepAliveFilter.java
    @Override
    public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
        Object message = writeRequest.getMessage();
        
        if (!isKeepAliveMessage(session, message)) {
            nextFilter.messageSent(session, writeRequest);
        }
    }

    @Override
    public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
        try {
            if (messageFactory.isRequest(session, message)) {
                Object pongMessage = messageFactory.getResponse(session, message);

                if (pongMessage != null) {
                    nextFilter.filterWrite(session, new DefaultWriteRequest(pongMessage));
                }
            }

            if (messageFactory.isResponse(session, message)) {
                resetStatus(session);
            }
        } finally {
            if (!isKeepAliveMessage(session, message)) {
                nextFilter.messageReceived(session, message);
            }
        }
    }

每次发送消息后或接收消息后,KeepAliveFilter会使用isKeepAliveMessage方法判断发送的消息是否为心跳消息。而这个方法是交给开发者实现的:

    private final KeepAliveMessageFactory messageFactory;

    private boolean isKeepAliveMessage(IoSession session, Object message) {
        return messageFactory.isRequest(session, message) || messageFactory.isResponse(session, message);
    }

因为这个“||"逻辑或的原因,当isRequest为真时,isResponse就不会调用了,而当isRequest为假时,isResponse才会调用。

所以会有这么一种现象:
发送心跳消息时,因为经过messageSent,所以会调用一次isRequest方法;
收到心跳回复时,因为经过messageReceived,所以会将isRequest和isResponse先调用一次,然后再在isKeepAliveMessage中重复调用一次isRequest和isResponse方法。

在这么一种逻辑下,当服务端没有回复心跳时,完全可以模拟接收到心跳的回复,假装自己已经收到心跳回复,避免因心跳超时问题而被服务端断开或自行断开。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值