java Netty通信例子

本文介绍了两个Netty通信的例子,展示了如何启动Netty服务器并处理UDP通信。在例子1中,通过JniNettyServer启动并配置多播地址,利用NioEventLoopGroup和Bootstrap创建并绑定端口,然后通过JniNettyHandler处理channelRead0方法中的数据。例子2中,NettyService根据配置文件启动,同样利用NioEventLoopGroup和Bootstrap,但处理方式由UdpServerHandler完成,接收到数据后通过webSocketServer发送信息。这两个实例都体现了Netty对socket通信的高级封装和简化。

个人理解:Netty是对socket的进一步封装

例子1:

1 启动

调用 start()

public class GdsApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(GdsApplication.class, args);
        new JniNettyServer("224.1.2.1", 55198).start();
    }
}

2 JniNettyServer

调用JniNettyHander类进行处理

@Slf4j
public class JniNettyServer {

    private InetSocketAddress groupAddress;
    private ChannelFuture f;

    public JniNettyServer(String host, int port) {
        groupAddress = new InetSocketAddress(host, port);
    }


    public JniNettyServer() {
    }

    public boolean isConnect() {
        return f.channel().isActive();
    }


    public void oneChannlStart(int port){
        try {
            EventLoopGroup group = new NioEventLoopGroup();
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioDatagramChannel.class)
                    .handler(new JniNettyHander());
            ChannelFuture sync = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }

    public void start1(){
        InetSocketAddress groupAddress = new InetSocketAddress("224.1.1.5", 55198);
        System.setProperty("java.net.preferIPv4Stack", "true");
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            NetworkInterface ni = NetUtil.LOOPBACK_IF;

            Enumeration<InetAddress> addresses = ni.getInetAddresses();
            InetAddress localAddress = null;
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (address instanceof Inet4Address){
                    localAddress = address;
                }
            }
            System.out.println(localAddress);
            Bootstrap bootstrap = new Bootstrap();
            //设置NioDatagramChannel
            bootstrap.group(group).channel(NioDatagramChannel.class)
                    .localAddress(localAddress,groupAddress.getPort())
                    //设置Option 组播
                    .option(ChannelOption.IP_MULTICAST_IF, ni)
                    //设置Option 地址
                    .option(ChannelOption.IP_MULTICAST_ADDR, localAddress)
                    //设置地址
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .handler(new JniNettyHander());

            //获取NioDatagramChannel
            NioDatagramChannel channel = (NioDatagramChannel) bootstrap.bind(groupAddress.getPort()).sync().channel();
            //加入组
            channel.joinGroup(groupAddress, ni).sync();
            //关闭Channel
            channel.closeFuture().await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();//优雅退出
        }
    }

    public void start() {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            InetAddress localAddress= OsInfoUtils.getLinuxLocalInetAddress();
            NetworkInterface ni = NetworkInterface.getByInetAddress(localAddress);
//            System.setProperty("java.net.preferIPv4Stack", "true");
//            NetworkInterface ni = NetUtil.LOOPBACK_IF;
//            Enumeration<InetAddress> addresses = ni.getInetAddresses();
//            InetAddress localAddress = null;
//            while (addresses.hasMoreElements()) {
//                InetAddress address = addresses.nextElement();
//                if (address instanceof Inet4Address){
//                    localAddress = address;
//                }
//            }

			/*String name = SystemPropManager.getInstance().getSysPropVal("UDP_NI_NAME");
			NetworkInterface ni = NetworkInterface.getByName(name);
			if(null==ni){
				System.out.println("组播【server】NetworkInterface为空。ni:" + name);
				return;
			}
			// NetworkInterface ni = NetUtil.LOOPBACK_IF;
			Enumeration<InetAddress> addresses = ni.getInetAddresses();
			InetAddress localAddress = null;
			while (addresses.hasMoreElements()) {
				InetAddress address = addresses.nextElement();
				if (address instanceof Inet4Address) {
					localAddress = address;
				}
			}*/

            Bootstrap b = new Bootstrap();
            b.group(group).channelFactory(new ChannelFactory<NioDatagramChannel>() {
                public NioDatagramChannel newChannel() {
                    return new NioDatagramChannel(InternetProtocolFamily.IPv4);
                }
            }).option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(2048 * 64))
                    .localAddress(localAddress, groupAddress.getPort()).option(ChannelOption.IP_MULTICAST_IF, ni)
                    .option(ChannelOption.SO_REUSEADDR, true).handler(new ChannelInitializer<NioDatagramChannel>() {
                @Override
                public void initChannel(NioDatagramChannel ch) throws Exception {
                    ch.pipeline().addLast(new JniNettyHander());
                }
            });

            NioDatagramChannel ch = (NioDatagramChannel) b.bind(groupAddress.getPort()).sync().channel();
            ch.joinGroup(groupAddress, ni).sync();
            // System.out.println("server");

            // ch.closeFuture().await();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // group.shutdownGracefully();
        }
    }

    public static void main(String[] args) {

        new JniNettyServer("224.0.0.20",9000).start();
    }
}

3、调用的方法

重写channelRead0()方法

public class JniNettyHander extends SimpleChannelInboundHandler<DatagramPacket> {

  @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket msg) throws Exception {
	//业务逻辑  需要推送的消息处理

	}
  @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        // We don't close the channel because we can keep serving requests.
    }
}

例子2:

1、启动

调用NettyService.start() 配置文件中读取IP 端口

@SpringBootApplication
public class SocketApplication {
    private static final Logger log = LoggerFactory.getLogger(SocketApplication.class);

    public static void main( String[] args ) {
        SpringApplication.run(SocketApplication.class,args);

        try {
            Properties properties =  PropertiesLoaderUtils.loadAllProperties("application.properties");
            String host = properties.getProperty("netty.host");
            String port = properties.getProperty("netty.port");
            if (StringUtils.isEmpty(host) || StringUtils.isEmpty(port)) {
                log.error("netty地址未配置");
                System.exit(0);
            }
            new NettyService(host, Integer.valueOf(port)).start();
        } catch (Exception e) {
            log.error("Netty server start error:", e);
            System.exit(0);
        }
    }
}

2、NettyService

实现 start() 调用UdpServerHandler

@Slf4j
public class NettyService {

    private String host;

    private final int port;

    public NettyService(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void start() throws Exception {
        // 主线程组
//        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 工作线程组  处理读写事件
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //创建客户端
            Bootstrap bootstrap = new Bootstrap();
            // 绑定线程池
            bootstrap.group(group)
                    // 指定使用的channel
                    .channel(NioDatagramChannel.class) //使用 NioSocketChannel 作为客户端的通道实现
                    .option(ChannelOption.SO_BROADCAST, true)
                    .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(1024*1024))
                    // 绑定监听端口
                    .localAddress(this.host, this.port)
                    // 绑定客户端连接时候触发操作
                    .handler(new UdpServerHandler());
            // 服务器异步创建绑定
            ChannelFuture cf = bootstrap.bind().sync();
            log.info(NettyService.class + "已启动,正在监听: " + cf.channel().localAddress());
            // 关闭服务器通道   //异步关闭通道(不是直接关闭,只是监听有关闭行为后在关闭)
            cf.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync(); // 释放线程池资源
//            bossGroup.shutdownGracefully().sync();
        }
    }
}

3、触发操作 UdpServerHandler

重写channelRead0()

public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
    private static final Logger log = LoggerFactory.getLogger(UdpServerHandler.class);

    private WebSocketServer webSocketServer = SpringContextUtil.getBean(WebSocketServer.class);

    @Override
    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {

        String receiveMsg = packet.content().toString(CharsetUtil.UTF_8);

        //判断接受到的UDP消息是否正确(未实现)
        if (!StringUtils.isEmpty(receiveMsg)) {
//            log.info("Received UDP Msg:" + receiveMsg);
            webSocketServer.sendInfo(receiveMsg);
        } else {
            log.error("Received UDP messsage error : null");
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        // We don't close the channel because we can keep serving requests.
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.info("与判读建立连接");
        //添加到channelGroup通道组
//        NettyChannelHandlerPool.channelGroup.add(ctx.channel());

//        ctx.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
//        ctx.pipeline().addLast(new StringDecoder(Charset.forName("GBK")));
        NettyChannelComponent.ctx = ctx;
//        NettyChannelComponent.clients.add(ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.info("与判读断开连接");
        //从channelGroup通道组删除
//        ChannelHandlerPool.channelGroup.remove(ctx.channel());
        NettyChannelComponent.ctx = null;
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值