物联网 基于netty构建mqtt协议规范(发布/订阅模式)

物联网 基于netty构建mqtt协议规范(发布/订阅模式)

简述

提供一对多的消息分发和消息生产/消费方的解耦,发布者无需知道订阅者的存在,两者通过 Broker 间接通信

源码(netty-sample-03-PubSub)

https://gitee.com/kcnf-iot/iot-sample/tree/master/netty/netty-sample-03

核心角色与工作流程

角色 职责
订阅者(Subscriber) 向 Broker 发送 SUBSCRIBE 请求,注册对某个主题的兴趣;接收来自 Broker 的推送消息。
发布者(Publisher) 向 Broker 发送 PUBLISH 请求,将消息发送到指定主题。
Broker(代理) 维护主题与订阅者列表的映射;接收发布的消息,并转发给对应主题的所有订阅者。

整体流程

复制代码
┌─────────────┐         ┌──────────────┐         ┌──────────────┐
│  Publisher  │ ──────► │   Broker     │ ◄────── │ Subscriber   │
│  (8888)     │  发布    │  (消息总线)   │  订阅    │  (9999)      │
└─────────────┘         └──────────────┘         └──────────────┘
                        端口: 7777

sub代码

复制代码
package com.jysemel.iot.subscriber;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class SubscriberServer {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new LineBasedFrameDecoder(1024));
                            p.addLast(new StringDecoder(StandardCharsets.UTF_8));
                            p.addLast(new StringEncoder(StandardCharsets.UTF_8));
                            p.addLast(new SubscriberHandler());
                        }
                    });

            ChannelFuture future = bootstrap.connect("127.0.0.1", 7777).sync();

            System.out.println("===========================================");
            System.out.println("   Subscriber 客户端已启动");
            System.out.println("===========================================");
            System.out.println("已连接到 Broker: 127.0.0.1:7777");
            System.out.println("功能: 订阅主题并接收消息");
            System.out.println("命令格式: SUB <topic>");
            System.out.println("示例: SUB news");
            System.out.println("输入 'quit' 退出");
            System.out.println("===========================================\n");

            Channel channel = future.channel();
            Scanner scanner = new Scanner(System.in);

            while (true) {
                String input = scanner.nextLine();
                if ("quit".equalsIgnoreCase(input)) {
                    break;
                }
                channel.writeAndFlush(input + "\n");
            }

        } finally {
            group.shutdownGracefully();
        }
    }
}

broker代码

复制代码
package com.jysemel.iot.broker;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.nio.charset.StandardCharsets;

public class BrokerServer {

    public void start() throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new LineBasedFrameDecoder(1024));
                            p.addLast(new StringDecoder(StandardCharsets.UTF_8));
                            p.addLast(new StringEncoder(StandardCharsets.UTF_8));
                            p.addLast(new BrokerHandler());
                        }
                    });

            ChannelFuture future = bootstrap.bind(7777).sync();
            System.out.println("===========================================");
            System.out.println("   Broker 服务器启动");
            System.out.println("===========================================");
            System.out.println("端口: 7777");
            System.out.println("功能: 消息路由和分发(充当 Redis 角色)");
            System.out.println("支持命令:");
            System.out.println("  - PUB <topic> <message>  : 发布消息");
            System.out.println("  - SUB <topic>            : 订阅主题");
            System.out.println("  - UNSUB <topic>          : 取消订阅");
            System.out.println("===========================================\n");

            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new BrokerServer().start();
    }
}

pub代码

复制代码
package com.jysemel.iot.publisher;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class PublisherServer {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new LineBasedFrameDecoder(1024));
                            p.addLast(new StringDecoder(StandardCharsets.UTF_8));
                            p.addLast(new StringEncoder(StandardCharsets.UTF_8));
                            p.addLast(new PublisherHandler());
                        }
                    });

            ChannelFuture future = bootstrap.connect("127.0.0.1", 7777).sync();

            System.out.println("===========================================");
            System.out.println("   Publisher 客户端已启动");
            System.out.println("===========================================");
            System.out.println("已连接到 Broker: 127.0.0.1:7777");
            System.out.println("功能: 发布消息到指定主题");
            System.out.println("命令格式: PUB <topic> <message>");
            System.out.println("示例: PUB news Hello World");
            System.out.println("输入 'quit' 退出");
            System.out.println("===========================================\n");

            Channel channel = future.channel();
            Scanner scanner = new Scanner(System.in);

            while (true) {
                String input = scanner.nextLine();
                if ("quit".equalsIgnoreCase(input)) {
                    break;
                }
                channel.writeAndFlush(input + "\n");
            }

        } finally {
            group.shutdownGracefully();
        }
    }
}

验证结果

相关推荐
Evelvnk1 分钟前
计算机学习资料
开发语言·人工智能·计算机·php
霖霖7143 分钟前
【ESP32笔记】ESP中的分区表
笔记·单片机·mcu·物联网
starzy19905 分钟前
Flink 任务调度 Graph 源码深度剖析:从 StreamGraph 到 ExecutionGraph 的三层演进
java·大数据·flink
权球物联分享物联网连接服务6 分钟前
农业无人机低空巡检:机库物联网卡联网逻辑与选型要点
物联网·无人机
Eyfcom7 分钟前
〖实战〗快运系统 Oracle 性能优化:从“能用”到“扛住双11”的 Java + Spring Boot 实战
java·oracle·性能优化·快递管理系统
geovindu12 分钟前
rust: Chain of Responsibility Pattern
开发语言·后端·设计模式·rust·责任链模式·行为模式
m0_5873830012 分钟前
碰碰好评卡功能落地全流程实战指南 附核心逻辑与常见问题解决方案
java·前端·数据库·后端·struts·需求分析
cheems952712 分钟前
从统一响应到 Swagger:一篇讲清微服务接口文档设计未命名
java·微服务·架构·状态模式
阿里嘎多学长15 分钟前
2026-10-14 GitHub 热点项目精选
开发语言·程序员·github·代码托管
迪康coolmu15 分钟前
迪康Defender网络准入控制系统落地实战:部署、配置与问题排查记录
运维·开发语言·网络·经验分享·php