netty创建tcp服务端+客户端

一.创建tcp服务端

@Slf4j
@Component
public class TcpServer {
   private static Channel serverChannel;
    /**
     * 创建服务端
     */
    @Async
    public void bind(int port) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();  //接受客户端连接并将SocketChannel注册到worker线程
        EventLoopGroup workerGroup = new NioEventLoopGroup(); //bossGroup开启的线程数为1,workerGroup开启的线程数为CPU核心数*2
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup) //设置NIO线程组
                    .channel(NioServerSocketChannel.class) //设置channel类型为NioServerSocketChannel
                    .childHandler(new ChannelInitializer<SocketChannel>() { //初始化handler
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline cp = socketChannel.pipeline();
                            cp.addLast(new StringDecoder(StandardCharsets.UTF_8));
                            cp.addLast(new StringEncoder(StandardCharsets.UTF_8));
                            cp.addLast(new ServerHandler(port)); //添加自定义handler
                        }
                    })
                    //.option(ChannelOption.SO_BACKLOG, 128)          //处理TCP连接队列大小缓存,默认50
                    .childOption(ChannelOption.SO_KEEPALIVE, true); //心跳机制开启,保证长连接不被断开
            serverChannel = serverBootstrap.bind(port).sync().channel();//绑定端口并开始接收入站数据
            log.info("TcpServer start success...");
            serverChannel.closeFuture().await(); //阻塞当前线程,直到关闭服务器通道
        } catch (Exception e) {
            log.error("TcpServer start fall!");
            e.printStackTrace();
        } finally {
            //优雅的关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    /**
     * 监听类
     */
    private class ServerHandler extends SimpleChannelInboundHandler {

        private int port;// 当前 端口

        public ServerHandler(int port) {
            this.port = port;
        }


        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            log.error(cause.getMessage());
            cause.printStackTrace();
            //ctx.close();
        }

        /**
         * 接收消息
         */
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
            String request = msg.toString();
            // 接收并处理来自客户端的消息
            log.info("{} ---> {}:{}", ctx.channel().remoteAddress(), this.port, request);
        }
    }


  /**
     * 发送数据
     *
     * @throws Exception
     */
    public void sendData(Object mgs) {
        try {
            serverChannel.writeAndFlush(mgs);
        } catch (Exception e) {
            log.error("发送消息错误!");
            e.printStackTrace();
        }

    }


}

下面展示一些 引用

   @Autowired
    TcpServer tcpServer;

tcpServer.bind(8080);
tcpServer.sendData(“我爱中国”);

二.创建tcp客户端,这里展示demo不是长连接了

1.下面展示一些 发送TCP给设备等待回复,35秒超时

 /**
     * 发送TCP给设备等待回复
     * 35秒超时
     *
     * @param ip
     * @param msg
     * @return
     */
    public String sendData(String ip,int port, Object msg) {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        EventLoopGroup group = new NioEventLoopGroup();
        Channel channel = null;
        Response r = new Response();
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInboundHandlerAdapter() {
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) {
                            ByteBuf byteBuf = (ByteBuf) msg;
                            String response = byteBuf.toString(StandardCharsets.UTF_8);
                            log.info("response msg: " + response);
                            byteBuf.release();
                            r.setMsg(response);
                            ctx.close();
                        }

                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                            log.error("exceptionCaught ->" + cause.getMessage());
                            cause.printStackTrace();
                            // ctx.close();
                        }
                    });
            ChannelFuture future = bootstrap.connect(ip, port).sync();
            channel = future.channel();
            log.info("{}  <- {}", ip, msg.toString());
            Channel finalChannel = channel;
            Future<?> executorServiceFuture = executorService.schedule(() -> {
                // 检查Channel是否仍然是活动状态
                if (finalChannel.isActive()) {
                    finalChannel.close();
                }
            }, 35, TimeUnit.SECONDS);
            ByteBuf byteBuf = Unpooled.copiedBuffer(msg.toString(), CharsetUtil.UTF_8); // 将消息内容转换为ByteBuf
            channel.writeAndFlush(byteBuf); // 发送
            channel.closeFuture().await();//异步等待,通道关闭后会往下执行
            executorServiceFuture.cancel(true); // 立刻中断
            return r.getMsg();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            executorService.shutdown(); // 清理资源
            if (channel != null) channel.close();
            group.shutdownGracefully();
        }
    }

 class Response {
        private String msg;

        public Response() {
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }
    }

2.下面展示一些 自定义TCP客户端发送数据Socket方式


    /**
     * 自定义TCP客户端发送数据
     *
     * @param ip
     * @param port
     * @return
     */
    public void sendDataDraw(String ip, int port, Object msg) {
        try {
            Socket socket = new Socket(ip, port);
            OutputStream os = socket.getOutputStream();
            PrintStream ps = new PrintStream(os, true, "UTF-8");
            ps.println(msg);
            ps.flush();
            socket.close();
            log.info("{}  <- {}", ip, msg.toString());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("连接不上设备!");
        }
    }

3.下面展示一些 发送tcp,不等待回复

/**
     * 发送tcp,不等待回复
     *
     * @param ip
     * @param port
     * @param msg
     */
    public void sendDataNoReply(String ip, int port, Object msg) {
        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) throws Exception {
                            ch.pipeline().addLast(new StringEncoder());
                        }
                    });
            // 连接到服务器
            ChannelFuture future = bootstrap.connect(ip, port).sync();
            Channel channel = future.channel();
            ByteBuf buffer = Unpooled.copiedBuffer(msg.toString(), CharsetUtil.UTF_8);
            channel.writeAndFlush(buffer);
            log.info("{}:{}  <- {}", ip, port, msg.toString());
            // 等待一段时间以确保数据发送完成
            Thread.sleep(1000);
        } catch (Exception e) {
            log.error("发送tcp数据失败:", e);
            throw new RuntimeException("发送数据失败或连接不上");
        } finally {
            // 关闭线程组
            group.shutdownGracefully();
        }
    }

最后发送 字符串 和 16进制 方式

Object msg你要发的内容

      ByteBuf byteBuf = null;
            if (format.equals("str")) {
                byteBuf = Unpooled.copiedBuffer(msg.toString(), CharsetUtil.UTF_8); // 将消息内容转换为ByteBuf
            } else {
                byte[] bytes = hexString2Bytes(msg.toString());// 将16进制字符串转换为字节数组
                byteBuf = Unpooled.wrappedBuffer(bytes); // 使用字节数组创建ByteBuf
            }
            channel.writeAndFlush(byteBuf); // 发送


    public static byte[] hexString2Bytes(String src) {
        byte[] bytes = new byte[src.length() / 2];
        for (int i = 0; i < bytes.length; i++) {
            int index = i * 2;
            int j = Integer.parseInt(src.substring(index, index + 2), 16);
            bytes[i] = (byte) j;
        }
        return bytes;
    }
Netty Quic是一种基于QUIC(Quick UDP Internet Connections)协议的高性能、低延迟的网络通信框架,它是由Netty项目集成支持的。QUIC是一种由Google设计并维护的下一代传输层协议,旨在改进TCP/IP协议栈的性能,特别是在移动网络环境下。 在Netty中实现Quic服务器和客户端通信,可以按照以下步骤操作: 1. **添加依赖**:在你的项目中引入Netty的Quic模块,例如如果你使用Maven,需要添加`io.netty:netty-quic`依赖。 2. **创建QuicServer**:服务器端需要创建一个`QuicServerBootstrap`实例,并配置监听地址和处理器链路。 ```java QuicServerBootstrap bootstrap = new QuicServerBootstrap(); bootstrap.group(...); // 设置事件组 bootstrap.channel(NioQuicServerChannel.class); bootstrap.childOption(ChannelOption.AUTO_READ, false); // 配置选项 bootstrap.childHandler(new MyQuicServerHandler()); // 自定义处理程序 bootstrap.bind(...); // 绑定端口 ``` 3. **创建QuicClient**:客户端则需要创建一个`QuicClientBootstrap`实例,设置目标地址,并连接到服务器。 ```java QuicClientBootstrap clientBootstrap = new QuicClientBootstrap(); clientBootstrap.group(...); // 设置事件组 clientBootstrap.channel(NioQuicClientChannel.class); clientBootstrap.handler(new MyQuicClientHandler()); QuicOptions options = new QuicOptions(); // 设置连接选项 options.maxIdleTimeMillis(5000); // 设置最大空闲时间 clientBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, options.connectTimeoutMillis); clientBootstrap.connect(...); // 连接服务器地址 ``` 4. **自定义Handler**:`MyQuicServerHandler`和`MyQuicClientHandler`是你自己实现的,用于处理数据收发、连接管理和错误处理等任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值