Netty初步之hello world

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();

}

}

}

相关推荐