Netty学习:搭建一个简单的Netty服务

Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性。换句话说,Netty是一个NIO框架,使用它可以简单快速地开发网络应用程序,比如客户端和服务端的协议。Netty大大简化了网络程序的开发过程比如TCP和UDP的 Socket的开发。Netty 已逐渐成为 Java NIO 编程的首选框架。

项目官方地址:http://netty.io/index.html

一. Netty 的优点:

API 使用简单,开发门槛低;

功能强大,预置了多种编解码功能,支持多种主流协议;

定制能力强,可以通过 ChannelHandler 对通信框架进行灵活的扩展;

性能高,通过与其它业界主流的 NIO 框架对比,Netty 的综合性能最优;

社区活跃,版本迭代周期短,发现的 BUG 可以被及时修复,同时,更多的新功能会被加入;

经历了大规模的商业应用考验,质量得到验证。在互联网、大数据、网络游戏、企业应用、电信软件等众多行业得到成功商用,证明了它完全满足不同行业的商用标准。

二. 搭建Netty服务:

添加pom依赖

Pom代码

<dependency>

<groupId>io.netty</groupId>

<artifactId>netty-all</artifactId>

<version>4.1.0.Final</version>

</dependency>

SimpleServer(服务端)

Java代码

packagecom.yingjun.netty.server;

importio.netty.bootstrap.ServerBootstrap;

importio.netty.channel.ChannelFuture;

importio.netty.channel.ChannelInitializer;

importio.netty.channel.ChannelOption;

importio.netty.channel.EventLoopGroup;

importio.netty.channel.nio.NioEventLoopGroup;

importio.netty.channel.socket.SocketChannel;

importio.netty.channel.socket.nio.NioServerSocketChannel;

/**

*

*Netty中,通讯的双方建立连接后,会把数据按照ByteBuf的方式进行传输,

*例如http协议中,就是通过HttpRequestDecoder对ByteBuf数据流进行处理,转换成http的对象。

*

*/

publicclassSimpleServer{

privateintport;

publicSimpleServer(intport){

this.port=port;

}

publicvoidrun()throwsException{

//EventLoopGroup是用来处理IO操作的多线程事件循环器

//bossGroup用来接收进来的连接

EventLoopGroupbossGroup=newNioEventLoopGroup();

//workerGroup用来处理已经被接收的连接

EventLoopGroupworkerGroup=newNioEventLoopGroup();

try{

//启动NIO服务的辅助启动类

ServerBootstrapb=newServerBootstrap();

b.group(bossGroup,workerGroup)

//配置Channel

.channel(NioServerSocketChannel.class)

.childHandler(newChannelInitializer<SocketChannel>(){

@Override

publicvoidinitChannel(SocketChannelch)throwsException{

//注册handler

ch.pipeline().addLast(newSimpleServerHandler());

}

})

.option(ChannelOption.SO_BACKLOG,128)

.childOption(ChannelOption.SO_KEEPALIVE,true);

//绑定端口,开始接收进来的连接

ChannelFuturef=b.bind(port).sync();

//等待服务器socket关闭。

f.channel().closeFuture().sync();

}finally{

workerGroup.shutdownGracefully();

bossGroup.shutdownGracefully();

}

}

publicstaticvoidmain(String[]args)throwsException{

newSimpleServer(9999).run();

}

}

SimpleServerHandler(服务端请求处理Handler)

Java代码

packagecom.yingjun.netty.server;

importio.netty.buffer.ByteBuf;

importio.netty.channel.ChannelHandlerContext;

importio.netty.channel.ChannelInboundHandlerAdapter;

publicclassSimpleServerHandlerextendsChannelInboundHandlerAdapter{

@Override

publicvoidchannelRead(ChannelHandlerContextctx,Objectmsg)throwsException{

System.out.println("SimpleServerHandler.channelRead");

ByteBufresult=(ByteBuf)msg;

byte[]result1=newbyte[result.readableBytes()];

//msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中

result.readBytes(result1);

StringresultStr=newString(result1);

//接收并打印客户端的信息

System.out.println("Clientsaid:"+resultStr);

//释放资源,这行很关键

result.release();

//向客户端发送消息

Stringresponse="helloclient!";

//在当前场景下,发送的数据必须转换成ByteBuf数组

ByteBufencoded=ctx.alloc().buffer(4*response.length());

encoded.writeBytes(response.getBytes());

ctx.write(encoded);

ctx.flush();

}

@Override

publicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause)throwsException{

//当出现异常就关闭连接

cause.printStackTrace();

ctx.close();

}

@Override

publicvoidchannelReadComplete(ChannelHandlerContextctx)throwsException{

ctx.flush();

}

}

SimpleServer(客户端)

Java代码

packagecom.yingjun.netty.server;

importio.netty.bootstrap.Bootstrap;

importio.netty.bootstrap.ServerBootstrap;

importio.netty.channel.ChannelFuture;

importio.netty.channel.ChannelInitializer;

importio.netty.channel.ChannelOption;

importio.netty.channel.EventLoopGroup;

importio.netty.channel.nio.NioEventLoopGroup;

importio.netty.channel.socket.SocketChannel;

importio.netty.channel.socket.nio.NioServerSocketChannel;

importio.netty.channel.socket.nio.NioSocketChannel;

publicclassSimpleClient{

publicvoidconnect(Stringhost,intport)throwsException{

EventLoopGroupworkerGroup=newNioEventLoopGroup();

try{

Bootstrapb=newBootstrap();

b.group(workerGroup);

b.channel(NioSocketChannel.class);

b.option(ChannelOption.SO_KEEPALIVE,true);

b.handler(newChannelInitializer<SocketChannel>(){

@Override

publicvoidinitChannel(SocketChannelch)throwsException{

ch.pipeline().addLast(newSimpleClientHandler());

}

});

//Starttheclient.

ChannelFuturef=b.connect(host,port).sync();

//Waituntiltheconnectionisclosed.

f.channel().closeFuture().sync();

}finally{

workerGroup.shutdownGracefully();

}

}

publicstaticvoidmain(String[]args)throwsException{

SimpleClientclient=newSimpleClient();

client.connect("127.0.0.1",9999);

}

}

SimpleServerHandler(客户端请求处理Handlerspringmvc+mybatis+spring 整合下载地址)

Java代码

packagecom.yingjun.netty.server;

importio.netty.buffer.ByteBuf;

importio.netty.channel.ChannelHandlerContext;

importio.netty.channel.ChannelInboundHandlerAdapter;

publicclassSimpleClientHandlerextendsChannelInboundHandlerAdapter{

@Override

publicvoidchannelRead(ChannelHandlerContextctx,Objectmsg)throwsException{

System.out.println("SimpleClientHandler.channelRead");

ByteBufresult=(ByteBuf)msg;

byte[]result1=newbyte[result.readableBytes()];

result.readBytes(result1);

System.out.println("Serversaid:"+newString(result1));

result.release();

}

@Override

publicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause)throwsException{

//当出现异常就关闭连接

cause.printStackTrace();

ctx.close();

}

//连接成功后,向server发送消息

@Override

publicvoidchannelActive(ChannelHandlerContextctx)throwsException{

Stringmsg="helloServer!";

ByteBufencoded=ctx.alloc().buffer(4*msg.length());

encoded.writeBytes(msg.getBytes());

ctx.write(encoded);

ctx.flush();

}

}

运行结果:

Java代码

SimpleClientHandler.channelRead

Serversaid:helloclient!

------------------------------------------

SimpleServerHandler.channelRead

Clientsaid:helloServer!

SimpleServerHandler.channelRead

Clientsaid:helloServer!