• Netty实现Socket


     从Java1.4开始, Java引入了non-blocking IO,简称NIO。NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念。传统的socket是基于stream的,它是单向的,有InputStream表示read和OutputStream表示写。而Channel是双工的,既支持读也支持写,channel的读/写都是面向Buffer。 NIO中引入的多路复用Selector机制(如果是linux系统,则应用的epoll事件通知机制)可使一个线程同时监听多个Channel上发生的事件。 虽然Java NIO相比于以往确实是一个大的突破,但是如果要真正上手进行开发,且想要开发出好的一个服务端网络程序,那么你得要花费一点功夫了,毕竟Java NIO只是提供了一大堆的API而已,对于一般的软件开发人员来说只能呵呵了。因此,社区中就涌现了很多基于Java NIO的网络应用框架,其中以Apache的Mina,以及Netty最为出名。

    一、Netty实现Socket
    1、Netty服务端示例:

    EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
        ServerBootstrap b = new ServerBootstrap(); // (2)
        b.group(bossGroup, workerGroup)  // (3)
         .channel(NioServerSocketChannel.class) // (4)
         .handler(new LoggingHandler())    // (5)
         .childHandler(new ChannelInitializer<SocketChannel>() { // (6)
             @Override
             public void initChannel(SocketChannel ch) throws Exception {
                 ch.pipeline().addLast(new DiscardServerHandler());
             }
         })
         .option(ChannelOption.SO_BACKLOG, 128)          // (7)
         .childOption(ChannelOption.SO_KEEPALIVE, true); // (8)
        
         // Bind and start to accept incoming connections.
         ChannelFuture f = b.bind(port).sync(); // (9)
        
         // Wait until the server socket is closed.
         // In this example, this does not happen, but you can do that to gracefully
         // shut down your server.
         f.channel().closeFuture().sync();
    } finally {
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }
    

    上面这段代码展示了服务端的一个基本步骤:
    (1)、初始化用于Acceptor的主"线程池"以及用于I/O工作的从"线程池";
    (2)、初始化ServerBootstrap实例, 此实例是netty服务端应用开发的入口;
    (3)、通过ServerBootstrap的group方法,设置(1)中初始化的主从"线程池";
    (4)、指定通道channel的类型,由于是服务端,故而是NioServerSocketChannel;
    (5)、设置ServerSocketChannel的处理器(此处不详述,后面的系列会进行深入分析)
    (6)、设置子通道也就是SocketChannel的处理器, 其内部是实际业务开发的"主战场"
    (7)、配置ServerSocketChannel的选项
    (8)、配置子通道也就是SocketChannel的选项
    (9)、绑定并侦听某个端口

    2、Netty客户示例:

    public class TimeClient {
        public static void main(String[] args) throws Exception {
            String host = args[0];
            int port = Integer.parseInt(args[1]);
            EventLoopGroup workerGroup = new NioEventLoopGroup(); // (1)
            
            try {
                Bootstrap b = new Bootstrap(); // (2)
                b.group(workerGroup); // (3)
                b.channel(NioSocketChannel.class); // (4)
                b.option(ChannelOption.SO_KEEPALIVE, true); // (5)
                b.handler(new ChannelInitializer<SocketChannel>() { // (6)
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new TimeClientHandler());
                    }
                });
                
                // Start the client.
                ChannelFuture f = b.connect(host, port).sync(); // (7)
    
                // Wait until the connection is closed.
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
            }
        }
    }
    

    客户端的开发步骤和服务端都差不多:
    (1)、初始化用于连接及I/O工作的"线程池";
    (2)、初始化Bootstrap实例, 此实例是netty客户端应用开发的入口;
    (3)、通过Bootstrap的group方法,设置(1)中初始化的"线程池";
    (4)、指定通道channel的类型,由于是客户端,故而是NioSocketChannel;
    (5)、设置SocketChannel的选项(此处不详述,后面的系列会进行深入分析);
    (6)、设置SocketChannel的处理器, 其内部是实际业务开发的"主战场";
    (7)、连接指定的服务地址;

    二、Netty实现SSLSocket
    netty创建服务端时,在初始化channl时,把handler加入ChannelPipeline时,在最开始那个handler设为SslHandler:

    SSLContext sslContext = SslUtil.createSSLContext(type ,path ,password); ///SslUtil自定义类
    SSLEngine sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); /// 是否使用客户端模式 sslEngine.setNeedClientAuth(false); ////是否需要验证客户端
    pipeline.addLast("ssl", new SslHandler(sslEngine));
    

    SslUtil类:

    private static volatile SSLContext sslContext = null;
    
    public static SSLContext createSSLContext(String type ,String path ,String password) throws Exception {
      if(null == sslContext){
         synchronized (SslUtil.class) {
          if(null == sslContext){
    
            KeyStore ks = KeyStore.getInstance(type); /// "JKS"          
            InputStream ksInputStream = new FileInputStream(path); /// 证书存放地址
              ks.load(ksInputStream, password.toCharArray());
              KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
              kmf.init(ks, password.toCharArray());
              SSLContext sslContext = SSLContext.getInstance("TLS");
              sslContext.init(kmf.getKeyManagers(), null, null);
          }
        }
      }
        return sslContext;
    }
    



  • 相关阅读:
    指针简单笔记
    Subway Lines (树链剖分+线段树)
    C#运动控制指示灯闪烁和系统复位(两个子窗体交互:一个子窗体按钮控制另外一个子窗体的方法)
    C# “|” 和 “||” “&”和“&&”区别
    2022/4/112022/4/16
    《Effective Modern C++》概览
    实验一 密码引擎4国䀄算法交叉测试
    实验一
    关于DDMS不显示进程的解决方法
    JNI接口native函数调用过程
  • 原文地址:https://www.cnblogs.com/exmyth/p/14170781.html
Copyright © 2020-2023  润新知