什么是netty?以下是官方文档的简单介绍:
The Netty project  is an effort to provide
an asynchronous event-driven network application framework and tools for rapid development of maintainable high performance and high scalability protocol servers and clients. In other words, Netty is
a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP/IP
socket server.

以下写一个简单的实例:
1.client细节分析

ChannelFactory是创建一个通道(和一次详细的通信实体关联如网络套接字)的主要接口。比方NioServerSocketChannelFactory 会创建一个Channel,有基于NIO的服务套接字作为底层的通信实体。一旦一个新的通道创建。那么相应的ChannelPipeline就会開始处理相关的ChannelEvents。
 

NioClientSocketChannelFactory会创建一个client的基于NIO的SocketChannel。利用非堵塞IO模型来高效处理这些并发的连接。当中有两种类型的线程, boss thread 和 worker thread,每一个NioClientSocketChannelFactory
有一个boss thread。它主要是有请求要发出时试图进行一次连接。连接成功后,将这个连接的通道交付给一个worker thread。接下来这个worker thread 为一个或多个通道运行非堵塞的读写服务。


ClientBootstrap仅仅是一个辅助函数,不会分配或者管理不论什么资源,管理资源是由构造器中指定的ChannelFactory完毕的。所以从同一个ChannelFactory衍生出多个ClientBootstrap是能够的。从而为不同的Channel应用不同的设置。connect()方法会依据指定的SocketAddress试图建立连接,假设本地地址没有设置,就会自己主动分配,等价于:
ClientBootstrap b = ....;
b.connect(remoteAddress, b.getOption("localAddress"));


静态方法 Channels.pipeline(ChannelHandler... handlers)用參数所指定的ChannelHandler 来创建一个新的ChannelPipeline,当然它们是有顺序的,我们也能够自己一个一个的加入。

 public static ChannelPipeline pipeline(ChannelHandler...
handlers) {
        if (handlers == null) {
            throw new NullPointerException( "handlers");
        }

        ChannelPipeline newPipeline = pipeline ();
        for (int i = 0; i < handlers. length;
i ++) {
            ChannelHandler h = handlers[i];
            if (h == null) {
                break;
            }
            newPipeline.addLast(ConversionUtil. toString(i), h);
        }
        return newPipeline;
    }

2. server端细节分析

服务器端构建的基本流程和client类似,仅仅是这里的ChannelFactory。Bootstrap 都要满足作为server的特性。

NioServerSocketChannelFactory创建server端的,基于NIO的ServerSocketChannel。仍然是非堵塞模式。

每一个绑定的ServerSocketChannel 有自身的boos thread,比方说打开监听了两个port 80,443。那么就会有两个boss thread,各自负责各自port的连接请求,直到那个port解绑定,然后将接受的连接请求交给worker
thread去处理。


这里是面向连接传输的ClientBootstrap 和  ServerBootstrap 。假设想用UDP的话就选 ConnectionlessBootstrap。

3. ChannelHandler的常见使用方法就会依据详细的事件类型做出详细的处理。牵扯到读写管道。并且有上下流的情况。


一个简单的netty样例:
TimeClientl.java
import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; public class TimeClient {
public static void main(String[] args) {
String host = args[0];
int port = Integer.parseInt(args[1]); 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 TimeClientHandler2());
}
});
bootstrap.connect(new InetSocketAddress(host, port)); //
} }

TimeClientHandler.java
import java.util.Date;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler; public class TimeClientHandler extends SimpleChannelHandler{
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
ChannelBuffer buffer = (ChannelBuffer)e.getMessage();
long currentTimeMills = buffer.readInt() * 1000L;
System.out.println(new Date(currentTimeMills));
e.getChannel().close();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
e.getCause().printStackTrace();
Channel c = e.getChannel();
c.close();
}
}


TimeServer.java
import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.ChannelGroupFuture;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class TimeServer {
public static ChannelGroup allChannels = new DefaultChannelGroup("time-server"); public static void main(String[] args) {
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 TimeServerHandler2(),
new TimeEncoder());
}
}); bootstrap.setOption("reuseAddr", true);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true); Channel channel = bootstrap.bind(new InetSocketAddress(8080)); allChannels.add(channel);
//waitForShutdownCommand(); this is a imaginary logic:for instance
//when there is accepted connection we close this server ;
if(allChannels.size() >=2){
ChannelGroupFuture f = allChannels.close();
f.awaitUninterruptibly();
factory.releaseExternalResources();
}
}
}


TimeServerHandler.java
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.SimpleChannelHandler; public class TimeServerHandler extends SimpleChannelHandler{
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
Channel ch = e.getChannel();
ChannelBuffer time = ChannelBuffers.buffer(4); //sizeof int
time.writeInt((int)(System.currentTimeMillis()/1000L + 2208988800L)); ChannelFuture cf = ch.write(time);
cf.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Channel ch = future.getChannel();
ch.close();
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
e.getCause().printStackTrace();
Channel c = e.getChannel();
c.close();
}
}

最新文章

  1. [转]Linux命令的返回值
  2. (python)图片处理Pillow模块的使用
  3. leetcode 124. Binary Tree Maximum Path Sum
  4. Android 在Windows上安装FFmpeg程序
  5. Android Service服务
  6. PreferenceActivity的使用
  7. iOS 让UIButton根据文字内容自动计算宽高
  8. 常用Nagios配置命令
  9. java压缩指定目录下的所有文件和文件夹的代码
  10. [Swift]LeetCode552. 学生出勤记录 II | Student Attendance Record II
  11. intellij 操作
  12. IPC rtsp转发服务器搭建
  13. QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类
  14. 4、pandas的数据筛选之isin和str.contains函数
  15. String.format的用法
  16. PAT甲题题解-1050. String Subtraction (20)-水题
  17. MapReduce运行原理
  18. isa class superclass metaclass
  19. Visual Studio 2010 SP1 在线安装后,找到缓存在本地的临时文件以便下次离线安装
  20. IOS 程序内部切换语言 的一种方法

热门文章

  1. ERP渠道管理添加验证和查询(二十二)
  2. ElastAlert告警
  3. spring boot 2.0.3+spring cloud (Finchley)6、配置中心Spring Cloud Config
  4. php 会话控制(禁用cookie后session为什么会失效?)
  5. windows下解决PyCharm控制台中文输出乱码
  6. Noip2018游记——AFO
  7. Linux-C基础编程
  8. View的工作原理(一) 总览View的工作流程
  9. zk节点扩充
  10. 《linux/unix设计思想》读后感