标签: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有三个关键指针readerIndex、 writerIndex 和 capacity,当数据写入ByteBuf时writeIndex会向后移动数据字的节数个位置(写入一个字节writeIndex向后移动一位),writeIndex最大不能超过capacity,当从ByteBuf读取数据时readerIndex会向后移动数据的字节数个位置(写入一个字节readIndex向后移动一位)。三个指针将ByteBuff划分成三个区,如下图所示:
+-------------------+------------------+------------------+ | 丢弃区域 | 可读区域 | 可写区域 | +-------------------+------------------+------------------+ | | | | 0 <= readerIndex <= writerIndex <= capacity
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<SocketChannel>() { @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<SocketChannel>() { @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
标签:src inf web text date() 存储 outbound erb 入门
原文地址:https://www.cnblogs.com/shenyuchong/p/12449861.html