Netty学习一

2021-04-09 05:26

阅读:278

标签:src   inf   web   text   date()   存储   outbound   erb   入门   

Netty概述

  Netty是一个是一款异步的事件驱动的网络应用程序框架,何为异步?异步的对立就是同步,同步就好比你有一个秘书,你叫你秘书外出采购Netty学习书籍,你在办公室等你秘书回来,期间什么事情都不能做,一直等到你秘书回来从她手上拿走书本后才可以匆匆忙忙上厕所;而异步就好比你叫你秘书外出采购Netty学习书籍后,你可以去访问Netty官网,参照官网的用户指导做个练习,你秘书回来后会通知你买到书籍与否。

Netty的用处

  首先Netty是一个网络应用框架,可以基于Netty开发一个基于http/https协议的服务器,这样你可以用浏览器访问你的服务;也可以基于它开发一个websocket协议的应用服务,这样可以实现前端与后台长连接全双工的交互;还可以基于它实现rpc应用等等。

Netty主要组件

  简单描述一下Netty主要组件,在后面会详细讨论。

  ChannelHandler:

    通道处理器,可以处理客户端和服务端之间传递的数据,在开发中一般用来做编解码处理和系统业务转发处理。

    ChannelHandler有两大常用子接口:一个是处理入栈数据的接口ChannelInboundHandler,另一个是处理出栈数据的接口ChannelOutboundHandler。

    出栈入栈:对服务端而言,入栈就是数据从客户端--->服务端的行为,出栈就是服务端--->客户端的行为;对于客户端而言,入栈就是服务端--->客户端的行为,出栈就是客户端--->服务端的行为(--->描述数据流动)。

  ChannelPipeline:

    ChannelPipeline可以简单看作一个ChannelHandler的双向链表(链表中实际上存储的是ChannelHandlerContext),在ChannelPipeline中调用addLast()方法可以将ChannelHandler添加到链表末端(实际末端还有一个tail节点,开发过程中不用管),ChannelPipeline运行过程中的调用链如下图所示:

                                                 I/O 请求
                                                      |
  +---------------------------------------------------+---------------+
  |                           ChannelPipeline         |               |
  |                                                  \|/              |
  |    +---------------------+            +-----------+----------+    |
  |    | 入栈处理器 n      |            | 出栈处理器  1          |    |
  |    +----------+----------+            +-----------+----------+    |
  |              /|\                                  |               |
  |               |                                  \|/              |
  |    +----------+----------+            +-----------+----------+    |
  |    | 入栈处理器 n-1        |            | 出栈处理器  2         |    |
  |    +----------+----------+            +-----------+----------+    |
  |              /|\                                  |               |
  |               |                                   |               |
  |               |                                  \|/              |
  |    +----------+----------+            +-----------+----------+    |
  |    | 入栈处理器 2          |            | 出栈处理器 m-1        |    |
  |    +----------+----------+            +-----------+----------+    |
  |              /|\                                  |               |
  |               |                                  \|/              |
  |    +----------+----------+            +-----------+----------+    |
  |    | 入栈处理器 1          |            | 出栈处理器 m          |    |
  |    +----------+----------+            +-----------+----------+    |
  |              /|\                                  |               |
  +---------------+-----------------------------------+---------------+
                  |                                  \|/
  +---------------+-----------------------------------+---------------+
  |               |                                   |               |
  |           [ 通道读 ]                         [ 通道写 ]            |
  +-------------------------------------------------------------------+
 

  EventLoop:

    事件循环器,可以看作是一个死循环线程,每次循环都会检测注册到自己的channel,若有事件(连接激活事件、通道可读事件、通道关闭事件等)发生会调用ChannelPipeline中第一个ChannelHandlerContext

  EventLoopGroup

    事件循环组,可以简单看作EventLoop的容器,默认会根据cpu核数乘以2来创建EventLoop

  BootStrap

    引导器,用于配置Netty程序相关内容以及启动Netty应用,其中group()方法用于添加EventLoopGroup,channel()方法用于指定channel的实现类handler()方法用接收一个ChannelInitializer对象,该对象重写的initChannel(SocketChannel socketChannel)方法,在该方法中调用socketChannel.pipeline().addLast()可以将处理器添加到ChannelPipeline中。  

  ByteBuf

    数据缓冲池,该缓冲区的特点是既可以读也可以写,ByteBuf有三个关键指针readerIndex、 writerIndex 和 capacity,当数据写入ByteBuf时writeIndex会向后移动数据字的节数个位置(写入一个字节writeIndex向后移动一位),writeIndex最大不能超过capacity,当从ByteBuf读取数据时readerIndex会向后移动数据的字节数个位置(写入一个字节readIndex向后移动一位)。三个指针将ByteBuff划分成三个区,如下图所示:

+-------------------+------------------+------------------+
| 丢弃区域           |  可读区域          |  可写区域         |
+-------------------+------------------+------------------+
|                   |                  |                  |
0      

 

Netty的hello world

  参考github上Netty的官方例子并简化后得到以下的Netty快速入门例子,为了方便排版,改造成两个文件,一个服务端和一个客户端。

  服务器端代码HelloWorldServer.java

package org.shenyuchong.simple_helloworld;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.util.Date;

public class HelloWorldServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new SimpleChannelInboundHandler(){
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, Object o) throws Exception {
                                    if(o instanceof ByteBuf){
                                        ByteBuf buf = (ByteBuf) o;
                                        byte[] msg = new byte[buf.readableBytes()];
                                        buf.readBytes(msg);
                                        System.out.println("从客户端收到消息:\n"+new String(msg,"utf-8"));
                                    }
                                    String msg = "你好客户端,现在时间是:"+ new Date();
                                    ByteBuf buf = Unpooled.wrappedBuffer(msg.getBytes("utf-8"));
                                    ctx.writeAndFlush(buf);
                                }
                            });
                        }
                    });

            ChannelFuture f = b.bind(8080).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

  客户端代码HelloWorldClient.java

package org.shenyuchong.simple_helloworld;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.Random;
public class HelloWorldClient {
    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new SimpleChannelInboundHandler(){
                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception{
                                    String msg = "我是客户端-"+ (new Random()).nextInt();
                                    ByteBuf buf = Unpooled.wrappedBuffer(msg.getBytes("utf-8"));
                                    ctx.writeAndFlush(buf);
                                }
                                @Override
                                protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
                                    if(o instanceof ByteBuf){
                                        ByteBuf buf = (ByteBuf) o;
                                        byte[] msg = new byte[buf.readableBytes()];
                                        buf.readBytes(msg);
                                        System.out.println("从服务器返回信息:\n"+new String(msg,"utf-8"));
                                    }
                                }
                            });
                        }
                    });
            b.connect("127.0.0.1", 8080).sync();
            while (true){
                Thread.sleep(5000);
                break;
            }
        } finally {
            group.shutdownGracefully();
        }
    }
}

 代码说明

  全部代码在https://github.com/yuchongshen/netty_example/tree/master/src/org/shenyuchong/simple_helloworld

  

  

Netty学习一

标签:src   inf   web   text   date()   存储   outbound   erb   入门   

原文地址:https://www.cnblogs.com/shenyuchong/p/12449861.html

上一篇:网站空间

下一篇:curl内容


评论


亲,登录后才可以留言!