一、概述
    Netty是由JBOSS提供的一个java开源框架。
    Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
 
二、体系结构图
   
三、Netty的核心结构
    Netty是典型的Reactor模型结构,在实现上,Netty中的Boss类充当mainReactor,NioWorker类充当subReactor(默认NioWorker的个数是当前服务器的可用核数)。
    在处理新来的请求时,NioWorker读完已收到的数据到ChannelBuffer中,之后触发ChannelPipeline中的ChannelHandler流。
    Netty是事件驱动的,可以通过ChannelHandler链来控制执行流向。因为ChannelHandler链的执行过程是在subReactor中同步的,所以如果业务处理handler耗时长,将严重影响可支持的并发数。
   
四、客户端和服务器端通信Demo

Server-main:

ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory(){
@Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new TimeServerHandler());
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.bind(new InetSocketAddress(1989));

ChannelFactory 是一个创建和管理Channel通道及其相关资源的工厂接口,它处理所有的I/O请求并产生相应的I/O ChannelEvent通道事件。这个工厂并自己不负责创建I/O线程。应当在其构造器中指定该工厂使用的线程池,这样我们可以获得更高的控制力来管理应用环境中使用的线程。

ServerBootstrap 是一个设置服务的帮助类。设置了一个继承自ChannelPipelineFactory的匿名类,用来作为ChannelPipeline通道,当服务器接收到一个新的连接,一个新的ChannelPipeline管道对象将被创建,并且所有在这里添加的ChannelHandler对象将被添加至这个新的ChannelPipeline管道对象。

    Server-Handler:

@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
//TimeServer
Channel ch = e.getChannel();
ChannelBuffer time = ChannelBuffers.buffer(8);
time.writeLong(System.currentTimeMillis());
ChannelFuture future = ch.write(time);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture arg0) throws Exception {
Channel ch = arg0.getChannel();
ch.close();
}
});
}
    Handler中是我们的业务逻辑,在Server的Handler里重载了channelConnected方法,当收到连接请求时,将当前服务器时间写入到Channel,并且在写完后触发关闭Channel。
    Client-main:

ChannelFactory factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
ClientBootstrap bootstrap = new ClientBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new TimeClientHandler());
}
});
bootstrap.setOption("tcpNoDelay",true);
bootstrap.setOption("keepAlive", true);
bootstrap.connect(new InetSocketAddress("127.0.0.1", 1989));
    Client端初始化Netty的过程和Server类似,只是将使用到的类替换为Client端的。
    Client-Handler:

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
ChannelBuffer buf = (ChannelBuffer)e.getMessage();
Long currentTimeMillis = buf.readLong();
System.out.println(new Date(currentTimeMillis));
e.getChannel().close();
}
    Client端的Handler里,我们将从服务器端接收到的信息转换为时间打印到控制台。
 
五、基于HTTP协议的服务器端实现
//HttpServerPipelineFactory.java
public class HttpServerPipelineFactory implements ChannelPipelineFactory {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("handler", new HttpServerHandler());
return pipeline;
}
}
    新建一个HttpServerPipelineFactory类,在getPipeline()方法中添加了对Http协议的支持。
// HttpServer.java
bootstrap.setPipelineFactory(new HttpServerPipelineFactory());
    在Server里面使用我们新建的HttpServerPipelineFactory。
//HttpServerHandler.java
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest)e.getMessage();
String uri = defaultHttpRequest.getUri();
byte[] data = defaultHttpRequest.getContent().array();
String content = URLDecoder.decode(new String(data),"utf-8").trim();
System.out.println(uri+"|"+content);
Channel ch = e.getChannel();
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
ChannelBuffer buffer = new DynamicChannelBuffer(2048);
buffer.writeBytes("200".getBytes("UTF-8"));
response.setContent(buffer);
response.setHeader("Content-Type", "text/html;charset=UTF-8");
response.setHeader("Content-Length", response.getContent().writerIndex());
if (ch.isOpen() && ch.isWritable()) {
ChannelFuture future = ch.write(response);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture arg0) throws Exception {
Channel ch = arg0.getChannel();
ch.close();
}
});
}
}
    在Handler里面我们可以直接拿到DefaultHttpRequest类型的对象,因为Netty已经用HttpRequestDecoder帮我们把接受到的数据都转换为HttpRequest类型了。
    使用了多个Handler后,通过下图,Netty的事件驱动就可以被很好的理解了:
  
    UpstreamEvent是被UpstreamHandler们自底向上逐个处理,DownstreamEvent是被DownstreamHandler们自顶向下逐个处理,这里的上下关系就是向ChannelPipeline里添加Handler的先后顺序关系。
 
六、总结
    Netty是一个简单却不失强大的架构。这个架构由三部分组成——缓冲(Buffer)、通道(Channel)、事件模型(Event Model)——所有的高级特性都构建在这三个核心组件之上。
 
七、深入学习
    http://netty.io/
    https://github.com/netty/netty

Netty框架入门的更多相关文章

  1. Netty学习_Netty框架入门教程:Netty入门之HelloWorld实现

    我们可能都学过Socket通信/io/nio/aio等的编程.如果想把Socket真正的用于实际工作中去,那么还需要不断的完善.扩展和优化.比如很经典的Tcp读包写包问题,或者是数据接收的大小,实际的 ...

  2. 【原创】NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战

    概述 本文演示的是一个Android客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo. 当前由于NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能. ...

  3. 【原创】NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战

    前言 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo.服务端将分别用MINA2和Netty4进行实现,而通信时服务端你只需选其一就行了.同 ...

  4. 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示

    前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...

  5. 【原创】NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示

    申明:本文由作者基于日常实践整理,希望对初次接触MINA.Netty的人有所启发.如需与作者交流,见文签名,互相学习. 学习交流 更多学习资料:点此进入 推荐 移动端即时通讯交流: 215891622 ...

  6. 【转】彻底搞透Netty框架

    本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希望给大家在实际开发实践.学习开源项目方面提供参考. Netty 是一个异步事件驱动的网络应用程序 ...

  7. CI框架入门1

    CI框架入门: 1.url的特点             2.目录结构/布局             3.MVC分别在哪里,如何依葫芦画瓢             4.安全性             ...

  8. CodeIgniter框架入门教程——第一课 Hello World!

    本文转载自:http://www.softeng.cn/?p=45 今天开始,我将在这里连载由我自己编写的<CodeIgniter框架入门教程>,首先,这篇教程的读着应该是有PHP基础的编 ...

  9. Android Netty框架的使用

    Netty框架的使用 1 TCP开发范例 发送地址---192.168.31.241 发送端口号---9223 发送数据 { "userid":"mm910@mbk.co ...

随机推荐

  1. logstash收集MySQL慢查询日志

    #此处以收集mysql慢查询日志为准,根据文件名不同添加不同的字段值input { file { path => "/data/order-slave-slow.log" t ...

  2. 分布式文件系统服务器FastDFS

    1. 什么是FastDFS FastDFS 是用 c 语言编写的一款开源的分布式文件系统.FastDFS 为互联网量身定制, 充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标, ...

  3. 【Visual Installer】如何注册自已的文件类型

    一.前言 这几天在做公司软件产品的安装包,产品有一个特定的后缀名为:.isbimqs,需要的功能是双击该后缀名文件后,会有一个启动程序launchRevit.exe去打开Revit,由Revit去打开 ...

  4. Unity3D手游开发日记(1) - 移动平台实时阴影方案

    阴影这个东西,说来就话长了,很多年前人们就开始研究出各种阴影技术,但都存在各种瑕疵和问题,直到近几年出现了PSSM,也就是CE3的CSM,阴影技术才算有个比较完美的解决方案.Unity自带的实时阴影, ...

  5. 洛谷 P2123 皇后游戏 解题报告

    P2123 皇后游戏 题意: 给定\(T\)组长为\(n\)的\(A\),\(B\)数组和\(C\)的计算方法,求一种排列方法,使最大的\(C\)最小化. 数据范围: \(1 \le T \le 10 ...

  6. 代码收藏系列--jquery--筛选器、事件绑定技巧

    Jquery筛选器的一些常用技巧,比如过滤属性等 /* 过滤获取没有含data-xsui-grid-colspan的节点 */$(this).find('.xsui-grid-cell:not([da ...

  7. [Wf2011]Chips Challenge

    两个条件都不太好处理 每行放置的个数实际很小,枚举最多放x 但还是不好放 考虑所有位置先都放上,然后删除最少使得合法 为了凑所有的位置都考虑到,把它当最大流 但是删除最少,所以最小费用 行列相关,左行 ...

  8. Xml中SelectSingleNode方法,xpath查找某节点用法

    Xml中SelectSingleNode方法,xpath查找某节点用法 最常见的XML数据类型有:Element, Attribute,Comment, Text. Element, 指形如<N ...

  9. 使用Masonry在UIScrollView内布局

    理论分析 首先,我们知道Autolayout改变了传统的以frame为主的布局思想.它其实是一种相对布局,核心思想是视图与视图之间的位置关系.比如,我们可以根据矩形的起始横坐标.纵坐标.长和宽这四个变 ...

  10. python中如何优雅续行和换行

    http://note.youdao.com/noteshare?id=8dbcb93991a89a6cfcd95580ed2198f0