天天看点

Netty网络编程二:Netty概述以及入门案例目录一:概述二:入门案例

本人写的Netty相关文章,全部基于版本4.1.33.Final

目录

1、概述
2、入门案例
           

一:概述

虽然原生的java给我们提供了非常强大NIO的功能,但是由于使用上的,众多网络编程上的问题,任然需要开发者自己开发维护,因为选择Netty这种基于原生NIO进行开发的框架来助于我们的开发。

二:入门案例

学任何框架都是从入门案例,netty也不例外,先搭建一个简单的服务端,客户端来理解Netty的便捷性。

需求:客户端连接服务端后,给服务端发送一条消息,服务端收到消息后,给客户端发送一条消息

服务端:

public class NettyServer {

    private int port;

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

    public void start(){
        // boss 是处理客户端连接的线程池
        // worker 是处理从客户端连接转发过来的IO数据的读写线程池
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try{
            // ServerBootstrap 对外一个便利创建服务端,Builder建造者设计模式
            ServerBootstrap sb = new ServerBootstrap();
            // 绑定线程池
            sb.group(boss,worker)
                    // 绑定channel 服务端绑定NioServerSocketChannel,此实现jdk的ServerSocketChannel
                    .channel(NioServerSocketChannel.class)
                    // 绑定服务端相关参数,可添加绑定多个参数
                    .option(ChannelOption.SO_BACKLOG, 1024) //指定此套接口排队的最大连接个数
                    // IO事件处理类,主要处理IO事件的读写
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 添加
                            pipeline.addLast(new NettyServerHandler());
                        }
                    });
            // 绑定端口,同步等待成功
            ChannelFuture cf = sb.bind(port).sync();
            System.out.println("服务已启动.................监听端口:" + port);
            // 等待服务器监听端口关闭
            cf.channel().closeFuture().sync();
        }catch (Exception e){
            // 优雅关闭线程资源
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        NettyServer nettyServer = new NettyServer(9090);
        nettyServer.start();
    }
}
           

handler处理器:

public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        byte[] buf = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(buf);
        String str = new String(buf, "utf-8");
        System.out.println("收到信息 : " + str);
        long currentTimeMillis = System.currentTimeMillis();
        ByteBuf writeBuf = Unpooled.copiedBuffer(("服务端发送的消息 : " + currentTimeMillis).getBytes());
        ctx.write(writeBuf);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        /**
         * 注意:此flush()方法是将消息发送队列中的消息写入到SocketChannel中发送给对方。
         * 从性能角度考虑,为了防止频繁地唤醒Selector进行消息发送,Netty的write()方法并不直接将消息写入SocketChannel中,
         * 调用write()方法只是把待发送的消息放到发送缓冲数组中,再通过调用flush()方法,将发送缓冲区中的消息全部写到SocketChannel中
         */
        System.out.println("channelReadComplete............");
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("消息异常.....exceptionCaught ");
        // 当发送异常时,关闭ctx,是否和ctx相关联的句柄等资源
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        System.out.println("用户事件触发....    userEventTriggered");
        super.userEventTriggered(ctx, evt);
    }
}
           

客户端代码:

public class NettyClient {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try{
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new NettyClientHandler());
                        }
                    });
            // 异步连接服务端
            ChannelFuture f = b.connect(new InetSocketAddress(9090)).sync();
            // 等待关闭
            f.channel().closeFuture().sync();
        }finally {
            //优雅退出,是否线程池资源
            group.shutdownGracefully();
        }
    }
}
           

客户端handler处理器:

public class NettyClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 当客户端与服务端链路建立成功后调用此方法
        System.out.println("channelActive...");
        ByteBuf message = Unpooled.copiedBuffer("fangyouyun client msg".getBytes());
        ctx.writeAndFlush(message);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("channelRead......");
        ByteBuf returnMsg = (ByteBuf)msg;
        byte[] bytes = new byte[returnMsg.readableBytes()];
        returnMsg.readBytes(bytes);
        System.out.println("收到服务端返回的消息 : " + new String(bytes));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        System.out.println(cause.getMessage());
    }
}
           

测试结果:

Netty网络编程二:Netty概述以及入门案例目录一:概述二:入门案例
Netty网络编程二:Netty概述以及入门案例目录一:概述二:入门案例

博客中案例代码:https://download.csdn.net/download/qq_22871607/11072379