arctan0 2012-09-25
Java的网络操作一直比较复杂,虽然说在加入NIO之后简单了些,但还不是我这些菜鸟玩得起的,由于存在大量低层操作和协议处理,所以在使用上面还是很难。迄今为止,还没有用NIO写出稳定可靠的网络操作,也许这和具体的应用需求较少也有关系吧。
大概也有人和我对NIO有同样的想法,他们最NIO进行了一些封装,所以就有了MIna和现在的Netty。
Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序[官方定义],整体来看其包含了以下内容:
1.提供了丰富的协议编解码支持,
2.实现自有的buffer系统,减少复制所带来的消耗,
3.整套channel的实现,
4.基于事件的过程流转以及完整的网络事件响应与扩展,
5.丰富的example。
有了Netty之后,网络编程最起码会大大简化,并且我们也不需要为性能问题担心,Netty并发两三万还是没什么太大问题的。已经有人进行过实验了。
本文主要是列举Netty初步使用的一个最基本的例子,具体的说明在代码中都有了,所以也不再重复。
java的学习是从Helloword开始的,Netty也从这里开始吧。
这里的例子比较简单,后面会慢慢的对Netty的一些复杂应用、Netty的原理进行一些解析。
1、ClientThread.java
packageHelloWord;
importstaticorg.jboss.netty.channel.Channels.pipeline;
importjava.net.InetSocketAddress;
importjava.util.concurrent.Executors;
importorg.jboss.netty.bootstrap.ClientBootstrap;
importorg.jboss.netty.channel.ChannelFuture;
importorg.jboss.netty.channel.ChannelPipeline;
importorg.jboss.netty.channel.ChannelPipelineFactory;
importorg.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
importorg.jboss.netty.handler.codec.string.StringDecoder;
importorg.jboss.netty.handler.codec.string.StringEncoder;
/**
*启动一个client线程,用来间歇性的发送消息
*@authorRansom
*/
publicclassClientThreadimplementsRunnable
{
privateChannelFuturefuture;
publicChannelFuturegetFuture()
{
returnfuture;
}
publicvoidsetFuture(ChannelFuturefuture)
{
this.future=future;
}
@Override
publicvoidrun()
{
/*
*实例化一个客户端Bootstrap实例,
*NioClientSocketChannelFactory是Netty默认提供的。
*两个参数,一个是boss的线程池,一个是worker执行的线程池。
*两个线程池都使用了java.util.concurrent.Executors中的线程池来创建。
*/
ClientBootstrapbootstrap=newClientBootstrap(
newNioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
/*
*设置piplineFactory,
*顾名思义,就是产生默认的pipline。
*pipline的实例是DefaultChannelPipeline
*提供了链式的事件通讯机制
*/
bootstrap.setPipelineFactory(newChannelPipelineFactory(){
/*
*(non-Javadoc)
*@seeorg.jboss.netty.channel.ChannelPipelineFactory#getPipeline()
*/
@Override
publicChannelPipelinegetPipeline()throwsException
{
/*
*在DefaultChannelPipeline的过滤器链中实现了
*encode、decode、handler
*其中encode实现自ChannelDownstreamHandler接口
*decode、Handler实现自ChannelUpstreamHandler接口
*也就说明了在client发送消息的时候,默认按照顺序会先调用decode
*在client接收到响应的时候,会按照顺序调用encode和Handler。
*后面会有文章专门将ChannelDownstreamHandler和ChannelUpstreamHandler的调用顺序。
*/
ChannelPipelinepipleline=pipeline();
pipleline.addLast("encode",newStringEncoder());
pipleline.addLast("decode",newStringDecoder());
pipleline.addLast("handler",newHandler());
returnpipleline;
}
});
/*
*与127.0.0.1建立长连接。
*/
future=bootstrap.connect(newInetSocketAddress("127.0.0.1",8080));
}
/**
*发送消息至server
*/
publicvoidsendMsg()
{
if(future==null)return;
Strings="HelloWord!";
future.getChannel().write(s);
}
}
2、Handler.java
packageHelloWord;
importorg.jboss.netty.channel.ChannelHandlerContext;
importorg.jboss.netty.channel.ExceptionEvent;
importorg.jboss.netty.channel.MessageEvent;
importorg.jboss.netty.channel.SimpleChannelUpstreamHandler;
/**
*client和server接收消息共用的handler
*由于两个都是继承自SimpleChannelUpstreamHandler,所以就写在一起了。
*@authorRansom
*
*/
publicclassHandlerextendsSimpleChannelUpstreamHandler
{
publicvoidmessageReceived(ChannelHandlerContextctx,MessageEvente)
throwsException
{
System.out.println("recivemessage,messagecontent:"+e.getMessage());
}
publicvoidexceptionCaught(
ChannelHandlerContextctx,ExceptionEvente)throwsException{
System.err.println("Clienthasaerror,Errorcause:"+e.getCause());
e.getChannel().close();
}
}
3、Server.java
packageHelloWord;
importstaticorg.jboss.netty.channel.Channels.pipeline;
importjava.net.InetSocketAddress;
importjava.util.concurrent.Executors;
importorg.jboss.netty.bootstrap.ServerBootstrap;
importorg.jboss.netty.channel.ChannelPipeline;
importorg.jboss.netty.channel.ChannelPipelineFactory;
importorg.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
importorg.jboss.netty.handler.codec.string.StringDecoder;
importorg.jboss.netty.handler.codec.string.StringEncoder;
/**
*在本地8080端口启动netty服务
*@authorRansom
*
*/
publicclassServer
{
publicstaticvoidmain(String[]args)
{
/*
*server的注释和client类似,在这里就不重复了
*但是需要注意的是server初始化的是ServerBootstrap的实例
*client初始化的是ClientBootstrap,两个是不一样的。
*里面的channelfactory也是NioServerSocketChannelFactory。
*/
ServerBootstrapbootstrap=newServerBootstrap(
newNioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(newChannelPipelineFactory()
{
@Override
publicChannelPipelinegetPipeline()throwsException
{
ChannelPipelinepipleline=pipeline();
pipleline.addLast("encode",newStringEncoder());
pipleline.addLast("decode",newStringDecoder());
pipleline.addLast("handler",newHandler());
returnpipleline;
}
});
bootstrap.bind(newInetSocketAddress(8080));
}
}
4、HelloWordMain.java
packageHelloWord;
/**
*Netty初步之helloword的client入口
*@authorRansom
*
*/
publicclassHelloWordMain
{
publicstaticvoidmain(String[]args)
{
ClientThreadr=newClientThread();
Threadt=newThread(r);
t.setName("clientthread");
t.start();
while(true)
{
try
{
Thread.sleep(3000);
}catch(InterruptedExceptione)
{
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
r.sendMsg();
}
}
}