Netty学习笔记(一) 客户端与服务端的搭建

Netty学习笔记(一) 客户端与服务端的搭建

客户端

ChannelFuture channelFuture = new Bootstrap()
                .group(new NioEventLoopGroup())
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel.pipeline().addLast(new StringEncoder());
                    }
                })
                // connect 异步非阻塞线程
                .connect(new InetSocketAddress("localhost", 8080));
        // 同步阻塞,等待nio线程建立连接
//        channelFuture.sync();
//        Channel channel = channelFuture.channel();
//        channel.writeAndFlush("hello world");

        //异步处理 addListener
        channelFuture.addListener(new ChannelFutureListener() {
            // nio建立连接后执行
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                Channel channel = channelFuture.channel();
                channel.writeAndFlush("ojbk");
            }
        });

上边这段程序就是Netty客户端的一段搭建的代码,一句句来看,

new Bootstrap就是开始创建一个启动类,那么这个启动类需要哪些配置呢?

首先,加载事件循环组EventLoopGroup,这里我们可以指定bossEventLoop和WorkerEventLoop,当然,不指定的话可以那么连接读写由同一个事件循环处理了就好,通过链式调用 .group加载进启动类

有group了,那么group管理哪个channel呢?,我们通过 . channel指定管理的channel类型

同时我们还要指定channel在建立连接后会进行哪些处理,需要指定handler

最后在进行connect的一个链接;

这一段结束完之后,我们就创建了一个channelFuture,其实我们见到Future就知道,这其实是一个异步类,因为在整个Netty中,所有的io操作都是异步的,所以我们需要一种用于在之后的某个时间确定其结果的方法,(因为直接将之转为channel并发送数据,我们并不知道是EventLoop的哪个线程来处理的)我们有两种方法,可以将channelFuture进行一个处理,进行收发数据的需要。首先,异步转同步,channelFuture.sysc() 方法就是将channelFuture转为同步方法,随后进行消息发送,当然,异步转同步肯定不是一种很优雅的解决方式,那么怎么优雅呢?,异步处理,怎么异步处理呢?其实Netty的ChannelFuture提供了addListener接口来配置监听,当EventLoop执行完操作,建立好连接后,那么哪个线程执行的,哪个线程来处理listener中的方法,在这个方法里,我们可以去write。值得注意的是,channel的write,也是一个异步操作,当客户端write后,他并不会主动去发送数据,什么时候会发呢?flush触发,也就是说,你可以一个channe不停地write,最后再执行一个flush,将之前的数据发出去,当然,要想马上发,那就是writeAndFlush()

ok,服务端

服务端

先上代码

 // 服务器启动,负责组装netty组件
        new ServerBootstrap()
                .group(new NioEventLoopGroup()) // BossEventloop 处理可连接事件  workEventloop 处理可读事件
                .channel(NioServerSocketChannel.class) // 选择服务器得ServerSocketChannel实现
                // 决定worker进行哪些操作
                // ChannelInitializer 初始化channel
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel.pipeline().addLast(new StringDecoder()); // bytebuf转字符串
                        //自定义handler
                        nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println(msg);
                                super.channelRead(ctx, msg);
                                //ctx.fireChannelRead(msg);//交给后续handler执行
                            }
                        });
                    }
                })
                .bind(8080);

这个,得和client对照着看,启动类不一样,服务端启的是ServerBootStrap(),后边的group,channel和childHandler都一样,那么服务端主要做一个消息的接收,怎么处理?就是利用childHandler去注册handler接收信息,比如说上段代码的new ChannelInitializer里边的initChannel,管道建立初始化的时候怎么做?EventLoop执行哪些handler?handler中做什么事?这些我们都在initChannel方法中去处理

nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println(msg);
                                super.channelRead(ctx, msg);
                                //ctx.fireChannelRead(msg);//交给后续handler执行
                            }
                        });

这一段,就是想socketchannel中添加了一个接收并处理消息的handler。

ok,发完了,接收到了,怎么关呢?

关闭客户端

我们都知道,Netty处理IO操作都是一步的,那么我们能直接在主程序里边去channe.close()吗?肯定不行,关不掉,那么怎么处理?首选,同步关闭

channel.closeFuture().sysc()

这一接口就是将channel转成同步,阻塞主线程,等待eventLoop执行完毕,进行后续操作

在这之后,worker.gracefullyShutdow() 优雅结束

二,异步处理

ChannelFuture closeFuture = channel.closeFuture();
                        closeFuture.addListener((future)->{
                            log.debug("closingggggggggg");
                            eventExecutors.shutdownGracefully();//group结束
                        });

还是addListener接口处理,哪个线程执行完了,优雅关闭。

当然,上边客户端,服务端的代码都是用了匿名内部类,只有一个方法,当然可以用lambda表达式去优化。

代码仅供批判

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值