一、什么是netty?
相信很多人和我一样,第一次接触到netty的时候,都是默默打开各种搜索引擎,然后输入“netty”。然后返回的结果都是各路大神的netty源码分析,以及对netty的解释。“Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序”,这是摘录自百度百科的对netty的描述。官网的表述是“Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients”,简单解释就是,netty是一个能够简单并且快速的构建网络应用的框架。我的简单理解是,netty是对Java Socket编程的封装,无论是阻塞还是非阻塞模式下的一个高度封装,能够让用户快速的搭建一个网络服务。
二、分析比较
- 阻塞方式(OIO)
当我第一次接触Java网络编程时,首先出现的就是如下代码。这段代码只给出了核心的一部分,这是socket编程中服务端的一个核心启动程序,当完成端口绑定之后,开始接收客户端的请求,也就是accept方法的调用。在阻塞模式下,如果当前没有请求进来,程序会一直阻塞在accept方法这里。如果是在单线程模式下,只有服务端处理完当前的任务之后,才能接收下一个请求。阻塞会给系统的吞吐量和并发量带来很大的影响。
ServerSocket serverSocket=new ServerSocket(8080);
while (true){
Socket socket=serverSocket.accept();//阻塞
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
byte readbytes[]=new byte[1024];
in.read(readbytes);
System.out.println(new String(readbytes));
out.write(readbytes);
out.flush();
out.close();
in.close();
}
- 非阻塞模式(NIO)
也就是当前的操作会直接返回,不会进行阻塞等到结果的到来,与OIO相比,OIO是面向流的操作,NIO是面向缓冲区。我们依然看一下服务端接收请求的代码。
String GREETING="Hello NIO.\r\n";
int port =1234;
ServerSocketChannel soc=ServerSocketChannel.open();
soc.socket().bind(new InetSocketAddress(port));
soc.configureBlocking(false);
ByteBuffer buffer=ByteBuffer.wrap(GREETING.getBytes());//缓冲区
while (true){
SocketChannel sc=soc.accept();//这里不会阻塞,结合Selector.select(),
//一个线程监听多个channel,也不会阻塞。
if (sc==null){
Thread.sleep(100);
}else {
printIn(sc.socket().getInputStream());
buffer.rewind();
sc.write(buffer);
sc.close();
}
}
NIO在提升性能的同时,其编程复杂度也相应的增长,稍不注意就会出现各种bug。所以其复杂度也让很多程序员望而生畏。此时netty因运而生。
- Netty
前边介绍了,netty是一个可以简单快速的构建一个高可用的网络编程框架。我们看看其服务端的简单实例,可以看出,netty编程的时候,简单的几行代码就可以搭建一个网络框架,也不需要去管理socket底层的复杂性,都已经进行高度封装。用户的业务逻辑可以通过handler来完成。所以用户只需要关注一些配置,然后编写相应的业务逻辑在handler中即可。
final EchoServerHandlerS handler=new EchoServerHandlerS();
EventLoopGroup boss=new NioEventLoopGroup();
EventLoopGroup work=new NioEventLoopGroup();
try{
ServerBootstrap b=new ServerBootstrap();
b.group(boss,work);
b.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(handler);
}
});
ChannelFuture future=b.bind().sync();
future.channel().closeFuture().sync();
}finally {
boss.shutdownGracefully().sync();
}
从上边比较来看,OIO会阻塞,系统吞吐量会降低,但是编程简单,NIO非阻塞,提高了系统的吞吐量,编程复杂。netty刚好结合了两者的有点。
netty是怎么两者兼顾的,我们从源码一步步着手,后续的源码分析都是采用4.1.63.Final版本
以上,有任何不对的地方,请指正,敬请谅解。