一個簡單的Netty-EchoDemo

本博客 貓叔的博客,轉載請申明出處

閱讀本文約 “4分鐘”

適讀人羣:Java-Netty 初級

Echo簡易通訊案例

版本:netty 4.1.*

申明:本文旨在重新分享討論Netty官方相關案例,添加部分個人理解與要點解析。

這個是InChat的案例地址,裏面補充了詳細的註釋,比起官方會容易看一點。

官方案例地址:https://netty.io/4.1/xref/io/...

正文

  • EchoClient(客戶端)
  • EchoClientHandler
  • EchoServer(服務端)
  • EchoServerHandler

要點介紹

  • SslContext

官方介紹:https://netty.io/4.1/api/io/n...

公共抽象類,安全套接字協議實現充當工廠SSLEngine和SslHandler。在內部,它通過JDK SSLContext或OpenSSL 實現SSL_CTX,還有關於它的使用方式,如果你需要ssl加密的話

  • SslContextBuilder

官方介紹:https://netty.io/4.1/api/io/n...

用於配置新SslContext以進行創建的構建器,其中包含多個方法這裏就不多補充,大家可以去看看

  • InsecureTrustManagerFactory

官方介紹:https://netty.io/4.1/api/io/n...

在TrustManagerFactory沒有任何驗證的情況下信任所有X.509證書的不安全因素

注意:切勿TrustManagerFactory在生產中使用它。它純粹是出於測試目的,因此非常不安全。
  • SelfSignedCertificate

官方介紹:https://netty.io/4.1/api/io/n...

生成臨時自簽名證書以進行測試

注意:切勿在生產中使用此類生成的證書和私鑰。它純粹是出於測試目的,因此非常不安全。它甚至使用不安全的僞隨機生成器在內部更快地生成

項目源碼

  • EchoClient
/**
 * @ClassName EchoClient
 * @Description 一個簡單的應答通訊的實例
 * @Author MySelf
 * @Date 2019/8/17 17:56
 * @Version 1.0
 **/
public final class EchoClient {

    //判斷是否加密
    static final boolean SSL = System.getProperty("ssl") != null;
    //監聽本地服務
    static final String HOST = System.getProperty("host", "127.0.0.1");
    //監聽端口
    static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
    //發送消息的大小,用於EchoClientHandler
    static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));

    public static void main(String[] args) throws Exception {
        //公共抽象類,安全套接字協議實現充當工廠SSLEngine和SslHandler。在內部,它通過JDK SSLContext或OpenSSL 實現SSL_CTX
        final SslContext sslCtx;
        if (SSL){
            //用於配置新SslContext以進行創建的構建器
            sslCtx = SslContextBuilder.forClient()
                    //用於驗證遠程端點證書的可信管理器
                    //InsecureTrustManagerFactory:在TrustManagerFactory沒有任何驗證的情況下信任所有X.509證書的不安全因素
                    //注:切勿TrustManagerFactory在生產中使用它。它純粹是出於測試目的,因此非常不安全。
                    .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
        }else {
            sslCtx = null;
        }
        //事件循環
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel sc) throws Exception {
                            ChannelPipeline p = sc.pipeline();
                            //瞭解SslContext的用法
                            if (sslCtx != null){
                                p.addLast(sslCtx.newHandler(sc.alloc(),HOST,PORT));
                            }
                            p.addLast(new EchoClientHandler());
                        }
                    });
            //這個sync後的代碼均會執行
            ChannelFuture f = b.connect(HOST,PORT).sync();
            System.out.println("before-----");

            //這個sync後的代碼不會執行
            f.channel().closeFuture().sync();
            System.out.println("after-----");
        }finally {
            group.shutdownGracefully();
        }
    }

}
  • EchoClientHandler
/**
 * @ClassName EchoClientHandler
 * @Description TODO
 * @Author MySelf
 * @Date 2019/8/17 18:06
 * @Version 1.0
 **/
public class EchoClientHandler extends ChannelInboundHandlerAdapter {

    private final ByteBuf firstMessage;

    public EchoClientHandler(){
        //獲取EchoClient的SIZE
        //Unpooled:ByteBuf通過分配新空間或通過包裝或複製現有字節數組,字節緩衝區和字符串來創建新的
        firstMessage = Unpooled.buffer(EchoClient.SIZE);
        for (int i = 0; i < firstMessage.capacity(); i++){
            firstMessage.writeByte((byte)i);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(firstMessage);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.write(msg);
    }

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

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
  • EchoServer
/**
 * @ClassName EchoServer
 * @Description 服務端
 * @Author MySelf
 * @Date 2019/8/17 18:15
 * @Version 1.0
 **/
public final class EchoServer {

    static final boolean SSL = System.getProperty("ssl") != null;
    static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));

    public static void main(String[] args) throws Exception {
        final SslContext sslCtx;
        if (SSL){
            //SelfSignedCertificate:生成臨時自簽名證書以進行測試
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
        }else{
            sslCtx = null;
        }

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        final EchoServerHandler serverHandler = new EchoServerHandler();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,100)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            if (sslCtx != null){
                                p.addLast(sslCtx.newHandler(ch.alloc()));
                            }
                            p.addLast(serverHandler);
                        }
                    });

            ChannelFuture f = b.bind(PORT).sync();

            f.channel().closeFuture().sync();

        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

}
  • EchoServerHandler
/**
 * @ClassName EchoServerHandler
 * @Description TODO
 * @Author MySelf
 * @Date 2019/8/17 18:14
 * @Version 1.0
 **/
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.write(msg);
    }

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

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

公衆號:Java貓說

學習交流羣:728698035

現架構設計(碼農)兼創業技術顧問,不羈平庸,熱愛開源,雜談程序人生與不定期乾貨。

Image Text

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章