netty 4*写一个简单的客户端和服务端。 自己的handler

服务端代码如下

package netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //以上我们创建了两个线程组
            //一是负责连接的请求. 二是负责真正的业务逻辑处理
            //在真正的运行过程中都是无限循环
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //这个是服务器的启动对象,配置参数
            serverBootstrap
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,128)//对列数
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new SerHandler());//pipeline 和 channel 是两个对象中,都有各自的引用。

                            //把自己写的handler 加入到管道中。

                        }
                    });
            System.out.println("server is starting ------------");
            ChannelFuture channelFuture = serverBootstrap.bind(6677).sync();
            channelFuture.channel().closeFuture().sync();//对关闭进行监听
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();



        }


    }
}

NioEventLoopGroup源码的解析

package netty;

import io.netty.util.NettyRuntime;

public class Test {
    public static void main(String[] args) {
        System.out.println(NettyRuntime.availableProcessors()); //获取的时cpu的核心数,也就是任务管理器的资源监视器的cpu个数。
    }
}

在这里插入图片描述
通过debug可以看到,这个线程组存在一个EventExecutor的数组中。



private static final int DEFAULT_EVENT_LOOP_THREADS;

    static {
        DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

        if (logger.isDebugEnabled()) {
            logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
        }
    }

对应的Handler

package netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/**
 * 因为我们自定义的Hander要继承自框架的才能让框架管理,如果没有是
 */
public class SerHandler extends ChannelInboundHandlerAdapter {

//这个就是读取数据的事件。也就是浏览器传过来的数据,被框架封装到了具体的对象中,让我们用handler来处理。ChannelHandlerContext这个对象中封装了所有的数据。包括channel   pipeline     二。这个msg 就是客户端传输过来的数据。  当有数据读取的时候,这个方法就会被触发。就像那个监听器模式,应该是调用了相应的方法。
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //这个方法是干嘛的呢。有上下文对象,我们可以拿到很多东西,还有msg
        System.out.println("ctx = " + ctx);
        //就像我们之前用ByteBuffer 一样。我们需要将数据封装到缓冲对象
        ByteBuf byteBuf = (ByteBuf) msg;//这个是netty封装后的buf 性能明显是比之前的高的。
        System.out.println("byteBuf.toString(CharsetUtil.UTF_8) = " + byteBuf.toString(CharsetUtil.UTF_8));



    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//数据读取完成之后
        //将数据写入,并刷新缓存
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端", CharsetUtil.UTF_8));

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //如果发生了异常,我们应该正常的关闭通道。
        ctx.close();
        //如果发生异常了调用。
    }
}

客户端代码

package netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        //客户需要一个事件循环组
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {
            //客户端我们启动的配置类是哪个呢  用的是netty的
            Bootstrap bootstrap = new Bootstrap();
            //因为这个每个客户端就是对应一个group 。server端是因为要处理accept 和 read 和 write 而分为的两个
            bootstrap.group(eventLoopGroup)//这个是线程组
                    .channel(NioSocketChannel.class) //客户端和服务器端就是差了一个  server  我们不需要设置child 队列和连接状态了。
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new CliHandler());
                        }
                    });
            System.out.println("client is started---");
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6677);//这个方法,直接会有返回值。也就是异步。关于ChannelFuture 后面继续分析
            channelFuture.channel().closeFuture().sync();//异步的监听的一个机制
        } finally {
            eventLoopGroup.shutdownGracefully();

        }


    }
}

客户端Handler

package netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

import java.nio.charset.Charset;

public class CliHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //当通道准备好了之后,就会触发这个方法。
        System.out.println("client :ctx = " + ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,服务端~ 🐶", CharsetUtil.UTF_8));//Unpooled 这个就是一个用来处理数据的工具类。


    }
//当有能读取的事件时,就会触发这个方法。
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                ByteBuf buf = (ByteBuf) msg;
        System.out.println("服务器说:"+((ByteBuf) msg).toString(CharsetUtil.UTF_8));//在nio中,我们的ByteBufer 是不能直接转的,需要 .arr()方法,也不用编码解码。
        System.out.println("ctx.channel().remoteAddress() = " + ctx.channel().remoteAddress());

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值