• Netty01 - 第一个网络通信程序


    首先在第一个程序开始学习

    Netty是一个基于NIO, 使用Reactor模式实现的网络通信框架.

    于是我们通过Reactor模式, 按图索骥, 大概认识一下Netty的主要组件如下: 

    核心组件: 

    1. 反应器组件: EventLoop - 封装了Selector和Thread, 对事件进行查询
    2. 处理器: Handler - 多个Handler组成流水线, 以责任链模式完成Channel中事件的处理
    3. 通道: Channel - 数据传输通道, 同时也是反应器组件的事件源
    4. 其它组件:
    • BootStrap: 使用建造者模式, 创建和配置基于Netty的Server端或者Client端的启动类
    • ByteBuf: 缓冲区

    代码1: Server端 - 启动类

    1. package netty.discard;
    2. import io.netty.bootstrap.ServerBootstrap;
    3. import io.netty.channel.ChannelFuture;
    4. import io.netty.channel.ChannelInitializer;
    5. import io.netty.channel.ChannelOption;
    6. import io.netty.channel.nio.NioEventLoopGroup;
    7. import io.netty.channel.socket.SocketChannel;
    8. import io.netty.channel.socket.nio.NioServerSocketChannel;
    9. /**
    10. * Instruction:丢弃信息服务器
    11. * Author:@author MaLi
    12. */
    13. public class DiscardServer {
    14. private int port;
    15. public DiscardServer(int port) {
    16. this.port = port;
    17. }
    18. public void startServer() {
    19. //创建组装器: 配置Netty的服务器端组件
    20. ServerBootstrap serverBootstrap = new ServerBootstrap();
    21. //1, 创建事件轮询组: 其中的每一个线程 - EventLoop对应一个Reactor或者SunReactor, 这里采用多线程的Reactor模式, 所有设置了两个轮询组
    22. NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);// 父轮询组: 用于查询 - 新连接事件
    23. NioEventLoopGroup workerGroup = new NioEventLoopGroup();//子轮询组: 用于查询 - 数据传输事件
    24. serverBootstrap.group(bossGroup, workerGroup); //由组装器设置两个轮询组
    25. //2, 创建通道类型并设置通道参数: 封装NIO中的Channel, 但是比Channel稍有区别(里面内置了PipeLine)
    26. NioServerSocketChannel socketChannel = new NioServerSocketChannel();
    27. //设置通道参数
    28. serverBootstrap.channel(socketChannel.getClass());
    29. serverBootstrap.localAddress(port);
    30. serverBootstrap.option(ChannelOption.SO_KEEPALIVE, true);
    31. //3, 设置Handler事件处理器
    32. serverBootstrap.childHandler(new ChannelInitializer() {
    33. @Override
    34. protected void initChannel(SocketChannel ch) throws Exception {
    35. ch.pipeline().addLast(new NettyDiscardHandler());
    36. }
    37. });
    38. try {
    39. //4, 绑定当前Channel到服务器端口 Create a new Channel and bind it.
    40. ChannelFuture channelFuture = serverBootstrap.bind().sync();//这里为什么创建一个Channel, 并绑定到服务器
    41. //关闭通道(为什么要关闭通道, 被关闭的是哪个通道 - ServerSocketChannel父通道, 父通道用于轮询新连接事件)
    42. // Returns the ChannelFuture which will be notified when this channel is closed. - 如果channel被关闭才会调用该回调
    43. // This method always returns the same future instance.
    44. // 5, 设置关闭channel时候的动作? --> 应用停止的时候父Channel才会被关闭, 释放掉底层的文件描述符
    45. channelFuture.channel().closeFuture().sync();
    46. } catch (InterruptedException e) {
    47. throw new RuntimeException(e);
    48. }finally {
    49. //6, 关闭两个事件轮询组, 进一步释放资源.
    50. workerGroup.shutdownGracefully();
    51. bossGroup.shutdownGracefully();
    52. }
    53. }
    54. public static void main(String[] args) {
    55. DiscardServer server = new DiscardServer(8888);
    56. server.startServer();
    57. }
    58. }

    代码2: Server端 - 处理器

    1. package netty.discard;
    2. import io.netty.channel.ChannelHandlerContext;
    3. import io.netty.channel.ChannelInboundHandlerAdapter;
    4. /**
    5. * Instruction:handler中的生命周期函数
    6. * Author:@author MaLi
    7. */
    8. public class NettyDiscardHandler extends ChannelInboundHandlerAdapter {
    9. // 如果有新连接被建立
    10. @Override
    11. public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    12. System.out.println("NettyDiscardHandler registed");
    13. super.channelRegistered(ctx);
    14. }
    15. @Override
    16. public void channelActive(ChannelHandlerContext ctx) throws Exception {
    17. System.out.println("NettyDiscardHandler actived");
    18. super.channelActive(ctx);
    19. }
    20. @Override
    21. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    22. System.out.println("data read");
    23. super.channelRead(ctx, msg);
    24. }
    25. @Override
    26. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    27. System.out.println("data read completed");
    28. super.channelReadComplete(ctx);
    29. }
    30. @Override
    31. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    32. System.out.println("data reading exception caught");
    33. super.exceptionCaught(ctx, cause);
    34. }
    35. }

    代码3: Client端

    1. package netty.discard;
    2. import java.io.IOException;
    3. import java.net.InetSocketAddress;
    4. import java.net.Socket;
    5. /**
    6. * Instruction:
    7. * Author:@author MaLi
    8. */
    9. public class DiscardClient {
    10. public static void main(String[] args) {
    11. Socket socket = new Socket();
    12. try {
    13. socket.connect(new InetSocketAddress("localhost", 8888)); //连接事件
    14. //socket.getOutputStream().write(1); // 数据发送事件
    15. socket.close();
    16. } catch (IOException e) {
    17. throw new RuntimeException(e);
    18. }
    19. }
    20. }

  • 相关阅读:
    4.1 设计模式_单例模式
    【考研数学】三. 微分方程
    lesson0-C++入门(6000余字详细配图讲解)
    Vite多页面应用简单构建
    同样是测试工程师,月薪8k的功能测试和月薪14k的自动化测试,差在了那里?
    Cholesterol-PEG-DBCO 胆固醇-聚乙二醇-二苯基环辛炔化学试剂
    GIS教程之将栅格数据 raster data发布到 Web 的 3 个简单步骤
    【从头构筑C#知识体系】1.1 类
    bm26 bm27 1
    【异步任务】异步线程后台执行解压缩,finished后通知调用者
  • 原文地址:https://blog.csdn.net/malipku/article/details/128058345