Netty基础介绍与框架搭建
2012-12-31 23:08 低调de草原狼 阅读(275) 评论(0) 编辑 收藏 举报问题所在:
目前为止,互联网上的通讯都是通过已有的应用程序或者软件库来实现。例如,我们最常使用的就是利用HTTP协议客户端(浏览器或者其他)从远程服务器上获取信息或者远程web服务。但是,大多数协议都不是为了我们的应用而特殊定制的,就像我们几乎不会用HTTP协议来传输大规模文件,发送电子邮件或是进行实时通讯。我们需要的是一个高度优化的应用框架可以支持我们特殊的需求。例如,你可以搭建一个HTTP server却能同时支持优化的AJAX聊天应用,大型文件传输等等。你甚至可以设计自己的一个网络通讯协议。
解决方法:
Netty是一个高效的、异步的、基于事件驱动的网络通讯框架。使用Netty 可以快速开发出可维护的,高性能、高扩展能力的协议服务及其客户端应用。也就是说,Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
“快速”和“简单”并不意味着会让你的最终应用产生维护性或性能上的问题。Netty是一个吸收了多种协议的实现经验,这些协议包括FTP,SMPT,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。
一些用户可能找到了某些同样声称具有这些特性的编程框架,因此你们可能想问Netty又有什么不一样的地方。这个问题的答案是Netty项目的设计哲学。从创立之初,无论是在API还是在其实现上Netty都致力于为你提供最为舒适的使用体验。虽然这并不是显而易见的,但你终将会认识到这种设计哲学将令你在阅读本指南和使用Netty时变得更加得轻松和容易。
客户端与服务器的搭建:
在详细介绍使用之前,先给出客户端与服务器端基本框架的搭建,以下程序以一个简单的时间服务为例,即客户端向服务器发送连接请求,服务器在收到请求之后就向客户端发送当前系统时间。在后续博客中会介绍每个环节的具体注意事项。废话就不多说了,先上代码:
服务器端:
TimeServer.java:
- package org.jboss.netty.example.time;
- 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 {
- //DefaultChannelGroup requires the name of the group as a constructor parameter. The group
- //name is solely used to distinguish one group from others.
- static final ChannelGroup allChannels = new DefaultChannelGroup("time-server" );
- public static void main(String[] args) throws Exception{
- ChannelFactory factory = new NioServerSocketChannelFactory(
- Executors.newCachedThreadPool(),
- Executors.newCachedThreadPool());
- ServerBootstrap bootstrap = new ServerBootstrap(factory);
- bootstrap.setPipelineFactory(new ChannelPipelineFactory(){
- public ChannelPipeline getPipeline(){
- return Channels.pipeline(
- new TimeServerHandler(),
- new TimeEncoder()
- );
- }
- });
- bootstrap.setOption("child.tcpNoDelay", true);
- bootstrap.setOption("child.keepAlive", true);
- Channel channel = bootstrap.bind(new InetSocketAddress(8080));
- allChannels.add(channel);
- waitForShutdownCommand();
- ChannelGroupFuture future = allChannels.close();
- future.awaitUninterruptibly();
- factory.releaseExternalResources();
- }
- }
TimeServerHandler.java:
- package org.jboss.netty.example.time;
- 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){
- // Channel ch = e.getChannel();
- // ChannelBuffer time = ChannelBuffers.buffer(4);
- // time.writeInt((int)(System.currentTimeMillis()/1000));
- //
- // ChannelFuture f = ch.write(time);
- // f.addListener(new ChannelFutureListener(){
- // public void operationComplete(ChannelFuture future){
- // Channel ch = future.getChannel();
- // ch.close();
- // }
- // });
- // }
- private static String a = "Hello";
- public TimeServerHandler(){
- System.out.println("Hello world " + a);
- }
- @Override
- public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
- UnixTime time = new UnixTime(System.currentTimeMillis() / 1000);
- ChannelFuture f = e.getChannel().write(time);
- f.addListener(ChannelFutureListener.CLOSE);
- }
- @Override
- public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
- TimeServer.allChannels.add(e.getChannel());
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e){
- e.getCause().printStackTrace();
- Channel ch = e.getChannel();
- ch.close();
- }
- }
TimeEncoder.java:
- package org.jboss.netty.example.time;
- import static org.jboss.netty.buffer.ChannelBuffers.buffer;
- import org.jboss.netty.buffer.ChannelBuffer;
- import org.jboss.netty.channel.ChannelHandlerContext;
- import org.jboss.netty.channel.Channels;
- import org.jboss.netty.channel.MessageEvent;
- import org.jboss.netty.channel.SimpleChannelHandler;
- public class TimeEncoder extends SimpleChannelHandler{
- @Override
- public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) {
- UnixTime time = (UnixTime) e.getMessage();
- ChannelBuffer buf = buffer(4);
- buf.writeInt((int)time.getValue());
- Channels.write(ctx, e.getFuture(), buf);
- }
- }
客户端代码:
TimeClient.java:
- package org.jboss.netty.example.time;
- 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.ChannelFuture;
- 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) throws Exception{
- String host = args[0];
- int port = Integer.parseInt(args[1]);
- // String host = "localhost";
- // int port = 8080;
- ChannelFactory factory = new NioClientSocketChannelFactory(
- Executors.newCachedThreadPool(),
- Executors.newCachedThreadPool());
- ClientBootstrap bootstrap = new ClientBootstrap(factory);
- bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
- public ChannelPipeline getPipeline(){
- return Channels.pipeline(
- new TimeDecoder(),
- new TimeClientHandler());
- }
- });
- bootstrap.setOption("tcpNoDelay", true);
- bootstrap.setOption("keepAlive", true);
- ChannelFuture future = bootstrap.connect(new InetSocketAddress(host,port));
- future.awaitUninterruptibly();
- if (!future.isSuccess()) {
- future.getCause().printStackTrace();
- }
- future.getChannel().getCloseFuture().awaitUninterruptibly();
- factory.releaseExternalResources();
- }
- }
TimeDecoder.java:
- package org.jboss.netty.example.time;
- import org.jboss.netty.buffer.ChannelBuffer;
- import org.jboss.netty.channel.Channel;
- import org.jboss.netty.channel.ChannelHandlerContext;
- import org.jboss.netty.handler.codec.frame.FrameDecoder;
- public class TimeDecoder extends FrameDecoder{
- // @Override
- // protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer){
- // if(buffer.readableBytes() < 4){
- // return null;
- // }
- // return buffer.readBytes(4);
- // }
- @Override
- protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer){
- if(buffer.readableBytes() < 4){
- return null;
- }
- return new UnixTime(buffer.readInt());
- }
- }
TimeClientHandler.java:
- package org.jboss.netty.example.time;
- import java.util.Date;
- import org.jboss.netty.buffer.ChannelBuffer;
- import org.jboss.netty.channel.ChannelHandlerContext;
- 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){
- // ChannelBuffer buf = (ChannelBuffer)e.getMessage();
- // long currentTimeMillis = buf.readInt() * 1000L;
- // System.out.println(new Date(currentTimeMillis));
- // e.getChannel().close();
- // }
- @Override
- public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){
- UnixTime m = (UnixTime)e.getMessage();
- System.out.println(m);
- e.getChannel().close();
- }
- }
共用数据结构:
UnixTime.java:
- package org.jboss.netty.example.time;
- import java.util.Date;
- public class UnixTime {
- private final long value;
- public UnixTime(long value){
- this.value = value;
- }
- public long getValue(){
- return value;
- }
- @Override
- public String toString(){
- return new Date(value * 1000L).toString();
- }
- }