那netty是什么东西呢?
Netty 努力提供一个异步的事件驱动网络程序框架和工具, 能快速开发易于维护的高性能, 高可扩展性的协议服务器和客户端.
换句话说, Netty 是一个NIO 客户端/ 服务器架构, 可以快速和容易的开发网络程序就像协议服务器和客户端.它极大的简化了网络开发, 如TCP 和UDP 套接字服务器的开发.带着来自于大量协议如FTP,SMTP, HTTP以及各种二进制和基于文本的传统协议的实现的经验, Netty被精心设计. 所以, Netty 成功的找到一种方法去实现简易开发, 性能, 稳定性和灵活性不冲突.
废话一下:本人认为netty还是比较深奥的东西,因为涉及到java NIO以及java多线程,虽然这些都被封装在netty里面,但作为一名优秀的程序员,你有必要对netty的源码进行剖析,同时,netty在设计上也有点让人纳闷,比如netty3和netty4的改动就很大,如果你在网上找到一个netty3的学习资料,那我只能很抱歉的告诉你,你可以放弃那资料了,可能在设计理念上没有多大的差别,但是,对原有netty3项目的维护将会带来一个很大的问题,关于netty3、4区别,我推荐你看一下http://www.oschina.net/translate/netty-4-0-new-and-noteworthy
同时,在学习netty之前,我建议可以去先了解一下nio、多线程并发编程,以及socket编程,这在我前面的博客中有讲到,还有未发布上去的会接着发上去
说明一下:本博客主要以入门为主,介绍运行的大致过程,至于源代码里面的细节接下来的博客中再一起深入探究吧
好吧,初步了解了netty之后,我们开始进行netty的初次出门吧
首先看一个最简单的客户端服务器的例子Discard(可以去github上面下载netty4 example)
/**
* 服务器
* @author chenx_000
*
*/
public class DiscardServer
{
private final int port;
public DiscardServer(int port)
{
this.port = port;
}
public void run() throws Exception
{
// 创建两个EventLoopGroup,一个充当register处理器bossGroup,bossGroup把处理过的通道交给workerGroup进行io操作
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try
{
// 一个服务器助手类
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
//用它来建立新accept的连接,用于构造serversocketchannel的工厂类
.channel(NioServerSocketChannel.class)
//在serverBootstrap内部用该handler去处理实例化的channel
.childHandler(new ChannelInitializer()
{
//当有新accept的时候,这个方法会调用
@Override
public void initChannel(SocketChannel ch)
throws Exception
{
ch.pipeline().addLast(new DiscardServerHandler());
}
});
// 绑定并等待accept到来的连接
ChannelFuture f = b.bind(port).sync();
//关闭服务器
f.channel().closeFuture().sync();
} finally
{
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception
{
int port;
if (args.length > 0)
{
port = Integer.parseInt(args[0]);
}
else
{
port = 8080;
}
new DiscardServer(port).run();
}
}
我们先看一下红色方法.childHandler(new ChannelInitializer
再看一下ServerBootstrap的属性
上面的childHandler就是childHandler(new ChannelInitializer
@Override
void init(Channel channel) throws Exception {
final Map, Object> options = options();
synchronized (options) {
channel.config().setOptions(options);
}
final Map, Object> attrs = attrs();
synchronized (attrs) {
for (Entry, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey
由红色部分代码可见刚才在类DiscardServer代码部分加入的channelInittiallizer被重新封装成channelinitalizer加入了channle的piplline中。而pipline中channelContext的handler进行IO操作。
在看一下DiscardServer中的实际的io处理类吧
public class DiscardServerHandler extends SimpleChannelInboundHandler {
private static final Logger logger = Logger.getLogger(
DiscardServerHandler.class.getName());
//读channel中的msg,该例子是一个discard,所以直接摒弃就是了
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf b = (ByteBuf) msg;
b.release();
}
//当netty发生错误,执行该方法
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
// Close the connection when an exception is raised.
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
cause);
ctx.close();
}
}
这是一个inboundhandler,就是对进来的io进行处理,以后会再讲讲channelhandler的
好吧,这就是服务器端了
好吧,接下来看一下客户端吧
public class DiscardClient
{
private final String host;
private final int port;
private final int firstMessageSize;
public DiscardClient(String host, int port, int firstMessageSize)
{
this.host = host;
this.port = port;
this.firstMessageSize = firstMessageSize;
}
public void run() throws Exception
{
EventLoopGroup group = new NioEventLoopGroup();
try
{
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.handler(new DiscardClientHandler(firstMessageSize));
// 尝试建立连接
ChannelFuture f = b.connect(host, port).sync();
// 等待直到连接断开
f.channel().closeFuture().sync();
} finally
{
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception
{
if (args.length < 2 || args.length > 3)
{
System.err.println("Usage: " + DiscardClient.class.getSimpleName()
+ " []");
return;
}
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3)
{
firstMessageSize = Integer.parseInt(args[2]);
}
else
{
firstMessageSize = 256;
}
new DiscardClient(host, port, firstMessageSize).run();
}
}
public class DiscardClientHandler extends SimpleChannelInboundHandler
{
private static final Logger logger = Logger
.getLogger(DiscardClientHandler.class.getName());
private final int messageSize;
private ByteBuf content;
private ChannelHandlerContext ctx;
public DiscardClientHandler(int messageSize)
{
if (messageSize <= 0)
{
throw new IllegalArgumentException("messageSize: " + messageSize);
}
this.messageSize = messageSize;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
this.ctx = ctx;
//初始化信息
content = ctx.alloc().directBuffer(messageSize).writeZero(messageSize);
// 发送已经初始化的信息
generateTraffic();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception
{
content.release();
}
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws Exception
{
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception
{
// 关闭连接当抛出一个异常
logger.log(Level.WARNING, "Unexpected exception from downstream.",
cause);
ctx.close();
}
long counter;
private void generateTraffic()
{
//冲洗出站套接字的缓冲区。刷新后,再次生成相同数量的传送。
ctx.writeAndFlush(content.duplicate().retain()).addListener(
trafficGenerator);
}
private final ChannelFutureListener trafficGenerator = new ChannelFutureListener()
{
@Override
public void operationComplete(ChannelFuture future) throws Exception
{
if (future.isSuccess())
{
generateTraffic();
}
}
};
}
到此为止,一个服务器客户端程序就已经完成了,现在可能知道netty是做什么,但对netty的内部还是很迷茫,这也应该很正常的,以后再继续netty4源码分析,一起进一步了解netty的体系吧