物联网 基于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();
        }
    }
}

验证结果

相关推荐
疯狂打码的少年4 小时前
【数据库技术】关系模型基本概念(关系/属性/元组/键)
java·服务器·数据库·笔记
OPEN-F4 小时前
C++进阶教程:继承与多态
开发语言·c++
Mr数据杨5 小时前
【Codex】用学生入学评估模块建立新生能力画像
android·java·javascript·django·codex·项目开发
2601_962056236 小时前
Spring Boot 入门 与 无法解析符号 springframework 的解决
java·spring boot·后端
luj_17686 小时前
大律师考核应重能力与科技素养
c语言·开发语言·c++·经验分享·算法
Thomas21436 小时前
Java scala 数组 链表
java·链表·scala
亚历克斯神6 小时前
低代码与 AI 的融合趋势——从可视化搭建到自然语言生成应用
java·spring·微服务
学长毕业设计7 小时前
基于SpringBoot的瑜伽馆网站的设计与实现(源码+文档+讲解视频)
java·spring boot·后端
一嘴一个橘子7 小时前
nginx 常用命令(在 nginx 目录下执行)
java
leonkay7 小时前
C# 特性(Attribute)——【1】基础讲解
开发语言·青少年编程·面试·c#·.net·个人开发