Netty下MQTT客户端实现

Netty下MQTT客户端实现

基于Netty对MQTT客户端的封装,代码如下: 

1、客户端

public class MqttClient extends BaseClient {
    private MqttConnectOptions info = new MqttConnectOptions();
    private MqttProducerProcess producerProcess;
    private MqttConsumerProcess consumerProcess;
    private MqttConsumer consumer;
    private MqttProducer producer;

    public MqttClient() {
        this.setSyncConnect(true);

        info.setClientIdentifier(StringsUtil.getUuid());
        MqttProducerProcessImpl producerProcessObj = new MqttProducerProcessImpl(this);
        MqttConsumerProcessImpl consumerProcessObj = new MqttConsumerProcessImpl(this);

        producerProcess = producerProcessObj;
        consumerProcess = consumerProcessObj;
        
        consumer = consumerProcess;
        producer = producerProcess;

    }
    
    public MqttConnectOptions mqttOptions() {
        return info;
    }

    public MqttConsumer consumer() {
        return consumer;
    }

    public MqttProducer producer() {
        return producer;
    }
    
    @Override
    public String getClientId() {
        return info.getClientIdentifier();
    }

    @Override
    protected void initConnect() {
        super.initConnect();
    }

    @Override
    public void sendMessage(String msg) {
        throw new MethodNotSupportException();
    }

    @Override
    protected void initSocketChannel(SocketChannel ch) {
        ClientProtocolProcess proObj = new ClientProtocolProcess(this, consumerProcess, producerProcess);
        super.initSocketChannel(ch);

        ch.pipeline().addLast("decoder", new MqttDecoder());
        ch.pipeline().addLast("encoder", MqttEncoder.INSTANCE);
        ch.pipeline().addLast("mqttHander", new MqttClientHandler(proObj));
    }

    @Override
    protected boolean loginInit() {
        NettyLog.debug("loginInit: " + info.toString());
        channel.writeAndFlush(ClientProtocolUtil.connectMessage(info));
        return true;
    }

    @Override
    public void disConnect() {
        if (channel != null) {
            NettyLog.debug("disConnect: ");
            channel.writeAndFlush(ClientProtocolUtil.disConnectMessage());
        }
    }
}

2、协议处理
 

public class MqttClientHandler extends SimpleChannelInboundHandler {
    private ClientProtocolProcess clientProtocolProcess;

    public MqttClientHandler(ClientProtocolProcess clientProtocolProcess) {
        this.clientProtocolProcess = clientProtocolProcess; 
    }
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msgx) throws Exception {
        if (msgx == null) {return ;}
        MqttMessage msg = (MqttMessage) msgx;
        NettyLog.debug("read: {}", msg.fixedHeader().messageType());
        MqttFixedHeader mqttFixedHeader = msg.fixedHeader();
        switch (mqttFixedHeader.messageType()) {
        case CONNACK:
            clientProtocolProcess.processConnectBack(ctx.channel(), (MqttConnAckMessage) msg);
            break;
        case UNSUBACK:
            clientProtocolProcess.processUnSubBack(ctx.channel(), msg);
            break;
        case PUBLISH:
            clientProtocolProcess.processPublish(ctx.channel(), (MqttPublishMessage) msg);
            break;
        case PUBACK:
            clientProtocolProcess.processPubAck(ctx.channel(), msg);
            break;
        case PUBREC:
            clientProtocolProcess.processPubRec(ctx.channel(), msg);
            break;
        case PUBREL:
            clientProtocolProcess.processPubRel(ctx.channel(), msg);
            break;
        case PUBCOMP:
            clientProtocolProcess.processPubComp(ctx.channel(), msg);
            break;
        case SUBACK:
            clientProtocolProcess.processSubAck(ctx.channel(), (MqttSubAckMessage) msg);
            break;
        default:
            break;
        }
    }
}

 
  

3、协议解析

public class ClientProtocolProcess {
    private final ClientProcess clientProcess;
    private final MqttConsumerProcess consumerProcess;
    private final MqttProducerProcess producerProcess;

    public ClientProtocolProcess(ClientProcess clientProcess, MqttConsumerProcess consumerProcess,
            MqttProducerProcess producerProcess) {
        this.clientProcess = clientProcess;
        this.consumerProcess = consumerProcess;
        this.producerProcess = producerProcess;
    }

    /**
     * B - S, B - P
     * @param channel
     * @param msg
     */
    public void processConnectBack(Channel channel, MqttConnAckMessage msg) {
        MqttConnAckVariableHeader mqttConnAckVariableHeader = msg.variableHeader();
        String sErrorMsg = "";
        switch (mqttConnAckVariableHeader.connectReturnCode()) {
        case CONNECTION_ACCEPTED:
            clientProcess.loginFinish(true, null);
            return;
        case CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD:
            sErrorMsg = "用户名密码错误";
            break;
        case CONNECTION_REFUSED_IDENTIFIER_REJECTED:
            sErrorMsg = "clientId不允许链接";
            break;
        case CONNECTION_REFUSED_SERVER_UNAVAILABLE:
            sErrorMsg = "服务不可用";
            break;
        case CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION:
            sErrorMsg = "mqtt 版本不可用";
            break;
        case CONNECTION_REFUSED_NOT_AUTHORIZED:
            sErrorMsg = "未授权登录";
            break;
        default:
            break;
        }

        clientProcess.loginFinish(false, new LoginException(sErrorMsg));
        channel.close();
    }

    /**
     * B - P (Qos1)
     * @param channel
     * @param mqttMessage
     */
    public void processPubAck(Channel channel, MqttMessage mqttMessage) {
        MqttMessageIdVariableHeader messageIdVariableHeader = (MqttMessageIdVariableHeader) mqttMessage
                .variableHeader();
        int messageId = messageIdVariableHeader.messageId();

        producerProcess.processPubAck(messageId);
        producerProcess.delMessage(messageId);
    }

    
    /**
     * B- P(Qos2)
     * @param channel
     * @param mqttMessage
     */
    public void processPubRec(Channel channel, MqttMessage mqttMessage) {
        MqttMessageIdVariableHeader messageIdVariableHeader = (MqttMessageIdVariableHeader) mqttMessage
                .variableHeader();
        int messageId = messageIdVariableHeader.messageId();

        producerProcess.processPubRec(messageId);
        producerProcess.sendPubRel(messageId);
    }

    /**
     * B - P (Qos2)
     * @param channel
     * @param mqttMessage
     */
    public void processPubComp(Channel channel, MqttMessage mqttMessage) {
        MqttMessageIdVariableHeader messageIdVariableHeader = (MqttMessageIdVariableHeader) mqttMessage
                .variableHeader();
        int messageId = messageIdVariableHeader.messageId();

        producerProcess.processPubComp(messageId);
        producerProcess.delMessage(messageId);
    }

    /**
     * B - S(Qos2)
     * @param channel
     * @param mqttMessage
     */
    public void processPubRel(Channel channel, MqttMessage mqttMessage) {
        MqttMessageIdVariableHeader messageIdVariableHeader = (MqttMessageIdVariableHeader) mqttMessage
                .variableHeader();
        int messageId = messageIdVariableHeader.messageId();
        this.consumerProcess.processPubRel(messageId);
        this.consumerProcess.sendPubCompMessage(messageId);
        this.consumerProcess.delMesage(messageId);
    }

    
    /**
     * B - S(Qos0, Qos1, Qos2)
     * @param channel
     * @param mqttMessage
     */
    public void processPublish(Channel channel, MqttPublishMessage mqttMessage) {
        MqttFixedHeader mqttFixedHeader = mqttMessage.fixedHeader();
        MqttPublishVariableHeader mqttPublishVariableHeader = mqttMessage.variableHeader();
        ByteBuf payload = mqttMessage.payload();
        String topciName = mqttPublishVariableHeader.topicName();
        MqttQoS qosLevel = mqttFixedHeader.qosLevel();
        int messageId = mqttPublishVariableHeader.packetId();
        byte[] bytes = ByteBufUtil.copyByteBuf(payload); 

        MessageData recviceMessage = MessageData.builder().topic(topciName).qos(qosLevel.value())
                .messageId(messageId).payload(bytes)
                .status(MessageStatus.PUB)
                .dup(mqttFixedHeader.isDup())
                .retained(mqttFixedHeader.isRetain()).build();

        if (qosLevel == MqttQoS.EXACTLY_ONCE) {
            this.consumerProcess.saveMesage(recviceMessage);
        }

        this.consumerProcess.processPublish(recviceMessage);

        switch (qosLevel) {
        case AT_MOST_ONCE:
            break;
        case AT_LEAST_ONCE:
            this.consumerProcess.sendPubAckMessage(messageId);
            break;
        case EXACTLY_ONCE:
            this.consumerProcess.sendPubRecMessage(messageId);
            break;
        default:
            break;
        }
    }
    
    /**
     * B - P
     * @param channel
     * @param mqttMessage
     */
    public void processSubAck(Channel channel, MqttSubAckMessage mqttMessage) {
        int messageId = mqttMessage.variableHeader().messageId();
        this.consumerProcess.processSubAck(messageId);
    }

    /**
     * B - S
     * @param channel
     * @param mqttMessage
     */
    public void processUnSubBack(Channel channel, MqttMessage mqttMessage) {
        int messageId;
        if (mqttMessage instanceof MqttUnsubAckMessage) {
            MqttUnsubAckMessage mqttUnsubAckMessage = (MqttUnsubAckMessage) mqttMessage;
            messageId = mqttUnsubAckMessage.variableHeader().messageId();
        } else {
            MqttMessageIdVariableHeader o = (MqttMessageIdVariableHeader) mqttMessage.variableHeader();
            messageId = o.messageId();
            NettyLog.error("not UnsubAckMessage:{}", messageId);
        }
        this.consumerProcess.processUnSubBack(messageId);
    }
}

完整源码请见github地址:

    https://github.com/xjc-opensource/ext-opensource-netty

你可能感兴趣的:(Netty下MQTT客户端实现)