Springboot3整合Netty进行消息传递

1.服务端

1.1 字符消息

  • NettyServer
/**
 * @author liu.wenxuan1
 * @Description: netty服务端处理字符消息 解码器问题 不能同时处理文件和字符
 */
public class NettyServer {

    private static final int PORT = 8080;

    public static void main(String[] args) throws Exception {
        // 服务启动器
        new ServerBootstrap()
                // bossGroup用于处理连接请求 workerGroup 用于处理I/O操作
                .group(new NioEventLoopGroup(), new NioEventLoopGroup())
                // TCP SOCKET通道为NioServerSocketChannel
                // UDP DatagramChannel
                .channel(NioServerSocketChannel.class)
                // 当客户端注册读写事件时 初始化Handler
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new StringEncoder());
                        ch.pipeline().addLast(new ServerHandler());
                    }
                })
                // 设置队列大小
                .option(ChannelOption.SO_BACKLOG, 128)
                // 保持连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .bind(PORT);
    }
}
  • ServerHandler
public class ServerHandler extends SimpleChannelInboundHandler<Object> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
        try {
            if (msg instanceof String) {
                System.out.println("服务端接受信息:");
                System.out.println(msg);
                ctx.writeAndFlush("Server response: " + msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws IOException {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Client disconnected");
        super.channelInactive(ctx);
        ctx.close();
    }
}

1.2 文件

public class NettyServerFile {

    private static final int PORT = 8081;

    public static void main(String[] args) throws Exception {
        // 服务启动器
        new ServerBootstrap()
                // bossGroup用于处理连接请求 workerGroup 用于处理I/O操作
                .group(new NioEventLoopGroup(), new NioEventLoopGroup())
                // TCP SOCKET通道为NioServerSocketChannel
                // UDP DatagramChannel
                .channel(NioServerSocketChannel.class)
                // 当客户端注册读写事件时 初始化Handler
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度
                        ch.pipeline().addLast(new ObjectEncoder());
                        ch.pipeline().addLast(new ServerHandlerFile());
                    }
                })
                // 设置队列大小
                .option(ChannelOption.SO_BACKLOG, 128)
                // 保持连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .bind(PORT);
    }
}
  • ServerHandlerFile
public class ServerHandlerFile extends ChannelInboundHandlerAdapter {

    private int byteRead;
    private volatile int start = 0;
    private String file_dir = "C:\\Users\\liu.wenxuan1\\Desktop";

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            System.out.println("接收到客户端信息");
            if (msg instanceof FileUploadFile) {
                System.out.println("\"文件上传中...");
                FileUploadFile ef = (FileUploadFile) msg;
                byte[] bytes = ef.getBytes();
                System.out.println("byteRead:" + bytes.length);
                byteRead = ef.getEndPos();
                String md5 = ef.getFile_md5();//文件名
                String path = file_dir + File.separator + md5;
                File file = new File(path);
                RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
                randomAccessFile.seek(start);
                randomAccessFile.write(bytes);
                start = start + byteRead;
                if (byteRead > 0) {
                    ctx.writeAndFlush(start);
                }
                System.out.println("文件已经读完--------" + byteRead);
                randomAccessFile.close();

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ctx.close();
        }

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}
  • FileUploadFile
public class FileUploadFile implements Serializable {


    private static final long serialVersionUID = 1L;
    private File file;// 文件
    private String file_md5;// 文件名
    private int starPos;// 开始位置
    private byte[] bytes;// 文件字节数组
    private int endPos;// 结尾位置

    public int getStarPos() {
        return starPos;
    }

    public void setStarPos(int starPos) {
        this.starPos = starPos;
    }

    public int getEndPos() {
        return endPos;
    }

    public void setEndPos(int endPos) {
        this.endPos = endPos;
    }

    public byte[] getBytes() {
        return bytes;
    }

    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public String getFile_md5() {
        return file_md5;
    }

    public void setFile_md5(String file_md5) {
        this.file_md5 = file_md5;
    }
}

2.客户端

  • NettyController
@RestController
@RequestMapping("/netty")
public class NettyController {

    @Autowired
    private NettyClient nettyClient;

    @PostMapping(value = "/sendMessage", consumes = "text/plain")
    @ResponseBody
    public void uploadFile(@RequestBody Stringmessage) {
        try {
            nettyClient.sendMessage(message);
            // 这里可以添加发送数据的逻辑,例如通过ChannelHandlerContext发送数据
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @PostMapping("/upload")
    public void uploadFile(@RequestBody FileUploadFile uploadFile) {
        try {
            nettyClient.uploadFile(uploadFile);
            // 这里可以添加发送数据的逻辑,例如通过ChannelHandlerContext发送数据
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • FileUploadFile
/**
 * package路径要和服务端一样才行
 */
@Data
public class FileUploadFile implements Serializable {

    private static final long serialVersionUID = 1L;

    private String filePath;

    private File file;// 文件

    private String fileName;// 文件名

    private int starPos;// 开始位置

    private byte[] bytes;// 文件字节数组

    private int endPos;// 结尾位置
}
  • ClientHandler
public class ClientHandler extends SimpleChannelInboundHandler<Object> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof String) {
            System.out.println("Client received: " + msg);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Client active");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws IOException {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
    }
}
  • ClientHandlerFile
public class ClientHandlerFile extends ChannelInboundHandlerAdapter {

    private int byteRead;
    private volatile int start = 0;
    private volatile int lastLength = 0;
    public RandomAccessFile randomAccessFile;
    private FileUploadFile fileUploadFile = new FileUploadFile();

    public ClientHandlerFile() {

    }

    public void send(FileUploadFile file, Channel ctx) {
        try {
            randomAccessFile = new RandomAccessFile(file.getFile(), "r");
            randomAccessFile.seek(file.getStarPos());
            lastLength = (int) randomAccessFile.length() ;
            System.out.println("文件长度:" + randomAccessFile.length());
            byte[] bytes = new byte[lastLength];
            if ((byteRead = randomAccessFile.read(bytes)) != -1) {
                file.setEndPos(byteRead);
                file.setBytes(bytes);
                ctx.writeAndFlush(file);
                System.out.println("已发送");
            } else {
                System.out.println("文件已经读完");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException i) {
            i.printStackTrace();
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("已连接");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//        if (msg instanceof Integer) {
//            start = (Integer) msg;
//            if (start != -1) {
//                randomAccessFile = new RandomAccessFile(fileUploadFile.getFile(), "r");
//                randomAccessFile.seek(start);
//                System.out.println("块儿长度:" + (randomAccessFile.length() / 10));
//                System.out.println("长度:" + (randomAccessFile.length() - start));
//                int a = (int) (randomAccessFile.length() - start);
//                int b = (int) (randomAccessFile.length() / 10);
//                if (a < b) {
//                    lastLength = a;
//                }
//                byte[] bytes = new byte[lastLength];
//                System.out.println("-----------------------------" + bytes.length);
//                if ((byteRead = randomAccessFile.read(bytes)) != -1 && (randomAccessFile.length() - start) > 0) {
//                    System.out.println("byte 长度:" + bytes.length);
//                    fileUploadFile.setEndPos(byteRead);
//                    fileUploadFile.setBytes(bytes);
//                    try {
//                        ctx.writeAndFlush(fileUploadFile);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                } else {
//                    randomAccessFile.close();
//                    ctx.close();
//                    System.out.println("文件已经读完--------" + byteRead);
//                }
//            }
//        }
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

}
  • NettyClient
@Component
public class NettyClient {

    private static final int MESSAGE_PORT = 8080;

    private static final int FILE_PORT = 8081;

    private static final String HOST = "10.82.224.183";

    private static final String PREFIX = "C:\\Users\\p30019551244\\Desktop\\";

    public void sendMessage(String message) throws Exception {
        // 启动类
        new Bootstrap()
                // 添加EventLoop
                .group(new NioEventLoopGroup())
                // 客户端channel实现
                .channel(NioSocketChannel.class)
                // 处理器
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    /**
                     * 连接后被调用
                     * @param ch
                     * @throws Exception
                     */
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new StringEncoder());
                        ch.pipeline().addLast(new ClientHandler());
                    }
                })
                .connect(HOST, MESSAGE_PORT)
                .sync()
                .channel()
                .writeAndFlush(message);
    }

    public void uploadFile(FileUploadFile fileUploadFile) throws Exception {
        // 启动类
        Channel channel = new Bootstrap()
                // 添加EventLoop
                .group(new NioEventLoopGroup())
                // 客户端channel实现
                .channel(NioSocketChannel.class)
                // 处理器
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    /**
                     * 连接后被调用
                     * @param ch
                     * @throws Exception
                     */
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度
                        ch.pipeline().addLast(new ObjectEncoder());
                        ch.pipeline().addLast(new ClientHandlerFile());
                    }
                })
                .connect(HOST, FILE_PORT)
                .sync()
                .channel();

        fileUploadFile.setFile(new File(PREFIX + fileUploadFile.getFileName()));
        fileUploadFile.setStarPos(0);
        int byteRead;
        int lastLength = 0;
        RandomAccessFile randomAccessFile;
        randomAccessFile = new RandomAccessFile(fileUploadFile.getFile(), "r");
        randomAccessFile.seek(fileUploadFile.getStarPos());
        lastLength = (int) randomAccessFile.length();
        System.out.println("文件长度:" + randomAccessFile.length());
        byte[] bytes = new byte[lastLength];
        if ((byteRead = randomAccessFile.read(bytes)) != -1) {
            fileUploadFile.setEndPos(byteRead);
            fileUploadFile.setBytes(bytes);
            channel.writeAndFlush(fileUploadFile);
            System.out.println("已发送");
        } else {
            System.out.println("文件已经读完");
        }
        randomAccessFile.close();

    }

    public static void main(String[] args) throws Exception {
        // 启动类
        Channel channel = new Bootstrap()
                // 添加EventLoop
                .group(new NioEventLoopGroup())
                // 客户端channel实现
                .channel(NioSocketChannel.class)
                // 处理器
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    /**
                     * 连接后被调用
                     * @param ch
                     * @throws Exception
                     */
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new StringEncoder());
                        ch.pipeline().addLast(new ClientHandler());
                    }
                })
                .connect(HOST, MESSAGE_PORT)
                .sync()
                .channel();

        // 创建Scanner对象,用于读取用户输入
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("输入消息");
            String userInput = scanner.nextLine();
            if ("exit".equalsIgnoreCase(userInput)) {
                break;
            }  else {
                channel.writeAndFlush(userInput);
            }
        }
    }

    public void testFile() throws Exception {
        // 启动类
        Channel channel = new Bootstrap()
                // 添加EventLoop
                .group(new NioEventLoopGroup())
                // 客户端channel实现
                .channel(NioSocketChannel.class)
                // 处理器
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    /**
                     * 连接后被调用
                     * @param ch
                     * @throws Exception
                     */
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度
                        ch.pipeline().addLast(new ObjectEncoder());
                        ch.pipeline().addLast(new ClientHandlerFile());
                    }
                })
                .connect(HOST, FILE_PORT)
                .sync()
                .channel();

        // 创建Scanner对象,用于读取用户输入
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("输入file来发送文件");
            String userInput = scanner.nextLine();
            if ("exit".equalsIgnoreCase(userInput)) {
                break;
            } else if ("file".equalsIgnoreCase(userInput)) {
                File file = new File("C:\\Users\\p30019551244\\Desktop\\demo.txt");
                FileUploadFile fileUploadFile = new FileUploadFile();
                fileUploadFile.setFile(file);
                fileUploadFile.setFileName("1234567.txt");
                fileUploadFile.setStarPos(0);
                int byteRead;
                int start = 0;
                int lastLength = 0;
                RandomAccessFile randomAccessFile;
                try {
                    randomAccessFile = new RandomAccessFile(fileUploadFile.getFile(), "r");
                    randomAccessFile.seek(fileUploadFile.getStarPos());
                    lastLength = (int) randomAccessFile.length() ;
                    System.out.println("文件长度:" + randomAccessFile.length());
                    byte[] bytes = new byte[lastLength];
                    if ((byteRead = randomAccessFile.read(bytes)) != -1) {
                        fileUploadFile.setEndPos(byteRead);
                        fileUploadFile.setBytes(bytes);
                        channel.writeAndFlush(fileUploadFile);
                        System.out.println("已发送");
                    } else {
                        System.out.println("文件已经读完");
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException i) {
                    i.printStackTrace();
                }
            } else {
                System.out.println("发送信息");
                channel.writeAndFlush(userInput);
            }
        }
    }
}
posted @   lwx_R  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示