服务器端
packagenetty; importio.netty.bootstrap.ServerBootstrap; importio.netty.channel.ChannelHandlerContext; importio.netty.channel.ChannelInboundHandlerAdapter; importio.netty.channel.ChannelInitializer; importio.netty.channel.nio.NioEventLoopGroup; importio.netty.channel.socket.nio.NioServerSocketChannel; importio.netty.channel.socket.nio.NioSocketChannel; importio.netty.handler.codec.string.StringDecoder; publicclassHelloServer { publicstaticvoidmain(String[] args) { // 1. 启动器,负责组装netty组件,启动服务器newServerBootstrap() // 2. BossEventLoop,WorkerEventLoop(Selector, thread), group组// 17. 客户端发送数据后,由某个EventLoop处理read事件,接收到ByteBuff// 这里可以分别指定boss和worker;boss只负责ServerSocketChannel上的accept链接,worker负责SocketChannel上的读写 .group(newNioEventLoopGroup()) // 3.选择服务器的ServersSocketChannel 实现 .channel(NioServerSocketChannel.class) // 4. boss负责处理链接,worker负责处理读写,决定了worker(child)执行哪些操作(handler) .childHandler( // 5. channel代表和客户端进行数据读写的通道,Initializer初始化,负责添加handlernewChannelInitializer<NioSocketChannel>() { // 12. 链接建立后,调用初始化方法protectedvoidinitChannel(NioSocketChannelnioSocketChannel) throwsException { // 6.添加具体handler// 18. read事件执行后,将ByteBuff还原成String字符串nioSocketChannel.pipeline().addLast(newStringDecoder()); // 将ByteBuff转换为字符串nioSocketChannel.pipeline().addLast(newChannelInboundHandlerAdapter(){ // 自定义的handler// 19. 执行read方法,打印信息publicvoidchannelRead(ChannelHandlerContextctx, Objectmsg) throwsException { // 接受消息System.out.println(msg); } }); } } ).bind(8080); } }
客户端
packagenetty; importio.netty.bootstrap.Bootstrap; importio.netty.channel.ChannelInitializer; importio.netty.channel.nio.NioEventLoopGroup; importio.netty.channel.socket.nio.NioSocketChannel; importio.netty.handler.codec.string.StringEncoder; publicclassHelloClient { publicstaticvoidmain(String[] args) throwsInterruptedException { // 8、添加启动器newBootstrap() // 9. 添加EventLoop .group(newNioEventLoopGroup()) // 10. 选择客户端channel实现 .channel(NioSocketChannel.class) // 11. 添加处理器handler .handler(newChannelInitializer<NioSocketChannel>() { // 12. 链接建立后,调用初始化方法protectedvoidinitChannel(NioSocketChannelnioSocketChannel) throwsException { // 16. 执行具体的handler,StringEncoder将“hello world”转成ByteBuffnioSocketChannel.pipeline().addLast(newStringEncoder()); } }) // 12. 链接服务端// 异步非阻塞,main发起了调用,真正执行connect的是nio线程 .connect("127.0.0.1", 8080) // 13. 阻塞方法,直到链接建立 .sync() // 14. 代表链接对象 .channel() // 15. 向服务器发送数据 .writeAndFlush("hello world!"); } }
说明
channel:数据通道
msg:流动的数据,最开始输入的是ByteBuf,经过pipeline加工,会变成其他类型对象,最后输出又变成ByteBuf
handler:数据处理器
- 可能会有多个,合在一起组成了pipeline,pipeline负责发布事件(如读,读写完成......)传播给每个handler,handler对自己感兴趣的事件进行处理(重写相应事件处理方法);
- handler分inbound(入站)和outbount(出站)两类;
eventloop:处理数据的工人
- 工人可以管理多个channel的io操作(多路复用),并且一旦工人负责某个channel,就要负责到底(绑定,保证线程安全);
- 工人既可以执行io操作,也可以进行任务处理,每个工人都有任务队列,对垒里可以存放多个channel的待处理任务,任务分为普通任务、定时任务;
- 工人按照pipeline顺序,依次按照handler规划处理数据,可以为每道工序指定不同的工人;