Netty浅析
来源:互联网 发布:sai mac 打不开 编辑:程序博客网 时间:2024/06/10 19:51
简介
Netty是一个异步网络IO框架,简单说就是帮我们专注于收发包的细节且提供高性能IO复用,在恰当的时候(如Tcp收满一个逻辑包后),回调我们的业务逻辑代码。
Netty基于NIO,整个Netty API体系都是异步的(可通过callback被动通知模式、Future主动通知模式进行后续的业务逻辑操作)。
组件介绍
Channels
代表一次具体的管道连接(文件设备或Socket),连接着两端的的读写。提供了基础的IO功能,如bind,connect,read,write等。使用Channel比Java的Socket更简单。有如下状态,当状态变化之后,就会出发相应的事件,最终ChannelPipeline调用他的ChannelHandlers进行处理。
ChannelUnregistered Channel创建,但是没有被注册到EventLoop中
ChannelRegistered Channel被注册到EventLoop中
ChannelActive Channel处于Active态,可能被读写
ChannelInactive Channel处于非Active态
EventLoop
EventLoopGroup包含多个EventLoop。EventLoop在生命周期内被绑定到一个线程上,Channel在生命周期内与一个EventLoop绑定,多个Channel可以被绑定在同一个EventLoop上。Handler
当特定的网络事件发生后,相应的业务逻辑Handler就会被执行。ChannelPipeline是一个ChannelHandler链条,用来传播处理inbound和outbound事件,执行顺序与被添加到pipeline中相同(inbound)。ChannelHandler分为inbound和outbound两种情况,对应的子接口分别为ChannelInboundHandler和ChannelOutboundHandler
ChannelHandlerContext
上下文。代表的是ChannelHandler和ChannelPipeline之间的关联关系Netty事件的流向
每个ChannelHandler都是一个业务逻辑处理单元,处理完成后,ChannelHandlerContext会将事件转发到下一个ChannelHandler,ChannelPipeline提供了一个ChnannleHandler链的容器。这就像工厂流水线和流水线上每个工种的关系。当我们实现业务的时候,只需要实现几个ChannelHandler,每个ChannelHandler负责一个业务功能,比如一个负责解码,一个负责业务处理,另一个负责异常处理等,然后用ChannelPipeline把ChannelHandler串起来就可以了。整个过程我们并不需要去了解底层的网络实现,大大加快了开发速度。而且这种实现还有一个好处,就是它把复杂的处理分解成了小的、可以复用的单元。高性能原理
1、使用epoll等IO复用技术。一个IO线程可以并发处理N个客户端连接和读写操作。避免频繁IO阻塞导致的线程挂起,这从根本上解决了传统同步阻塞IO一连接一线程模型。2、内存使用优化。接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写。
3、文件传输采用transferTo(如果是linux系统则为),减少无用内存复制。
4、使用内存池。
5、操作无锁化
Demo
详情参考
阻塞IO
public class MyServer { public static class MyRun implements Runnable{ private Socket socket = null; public MyRun(Socket socket) { this.socket = socket; } public void run() { BufferedReader bufferedReader = null; PrintWriter printWriter = null; try { bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = bufferedReader.readLine(); printWriter = new PrintWriter(socket.getOutputStream(), true); if (line.length() < 1){ printWriter.println("it is null"); return; } System.out.println(line); if ("get time".equals(line)){ printWriter.println(new Date().toString()); }else{ printWriter.println("isn't ok"); } } catch (IOException e) { e.printStackTrace(); try { if (bufferedReader != null) { bufferedReader.close(); } if (printWriter != null){ printWriter.close(); } if (socket != null){ socket.close(); } }catch (Exception ex){ ex.printStackTrace(); } } } } public static void main(String[] args) { int port = 8080; ServerSocket serverSocket = null; Executor executor = Executors.newFixedThreadPool(100); try { serverSocket = new ServerSocket(port); while (true){ Socket accept = serverSocket.accept(); executor.execute(new MyRun(accept)); } } catch (IOException e) { e.printStackTrace(); }finally { if (serverSocket != null){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }}
非阻塞IO
public class NioServer { public static void main(String[] args) { new Thread(new MyRun()).start(); } public static class MyRun implements Runnable { private Selector selector; private ServerSocketChannel serverSocketChannel; private volatile boolean stop = false; public MyRun() { try { selector = Selector.open(); serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.socket().bind(new InetSocketAddress(8080), 1024); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { e.printStackTrace(); } } public void run() { while (!stop) { try { selector.select(1000); Set<SelectionKey> selectionKeys = selector.selectedKeys(); for (Iterator<SelectionKey> iterator = selectionKeys.iterator(); iterator.hasNext(); ) { SelectionKey key = iterator.next(); iterator.remove(); try { handlerKey(key); } catch (Exception e) { if (key != null) { key.cancel(); if (key.channel() != null) { key.channel().close(); } } } } } catch (IOException e) { e.printStackTrace(); } } System.out.println("server is stop"); if (selector != null) { try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } if (serverSocketChannel != null) { try { serverSocketChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } private void handlerKey(SelectionKey key) throws IOException { if (key.isValid()) { if (key.isAcceptable()) { ServerSocketChannel channel = (ServerSocketChannel) key.channel(); SocketChannel accept = channel.accept(); accept.configureBlocking(false); accept.register(selector, SelectionKey.OP_READ); } if (key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); int read = channel.read(byteBuffer); if (read > 0) { byteBuffer.flip(); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); String recive_msg = new String(bytes, "utf-8"); System.out.println(recive_msg); String rep_msg = "get time".equals(recive_msg) ? new Date().toString() : "bad time"; dowrite(channel, rep_msg); } else if (read < 0) { key.cancel(); channel.close(); } else { } } } } private void dowrite(SocketChannel channel, String rep) throws IOException { if (rep != null && rep.length() > 0) { byte[] bytes = rep.getBytes(); ByteBuffer wrte = ByteBuffer.allocate(bytes.length); wrte.put(bytes); wrte.flip(); channel.write(wrte); } } }}
异步IO
public class AIOServer { private AsynchronousServerSocketChannel serverSocketChannel; private CountDownLatch countDownLatch = new CountDownLatch(1); public AIOServer() { try { serverSocketChannel = AsynchronousServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8080),1024); } catch (IOException e) { e.printStackTrace(); } } public void go() throws IOException { try { doAccept(); countDownLatch.await(); }catch (Exception e){ serverSocketChannel.close(); } } private void doAccept() { serverSocketChannel.accept(this, new CompletionHandler<AsynchronousSocketChannel, AIOServer>() { public void completed(final AsynchronousSocketChannel socketChannel, AIOServer aioServer) { //必须加这句才能接收其他的客户端连接,形成一个循环 aioServer.serverSocketChannel.accept(aioServer,this); final ByteBuffer byteBuffer = ByteBuffer.allocate(1024); socketChannel.read(byteBuffer, byteBuffer, new CompletionHandler<Integer, ByteBuffer>() { public void completed(Integer a, ByteBuffer bf) { byteBuffer.flip(); byte[] bytes = new byte[bf.remaining()]; bf.get(bytes); try { String msg = new String(bytes, "utf-8"); System.out.println(msg); String rep = "get time".equals(msg) ? new Date().toString() : "bad time"; doWrite(rep, socketChannel); } catch (Exception e) { try { socketChannel.close(); } catch (IOException ex) { e.printStackTrace(); } } } private void doWrite(String rep, final AsynchronousSocketChannel result) throws IOException { byte[] bytes = rep.getBytes("utf-8"); ByteBuffer bf = ByteBuffer.allocate(bytes.length); bf.put(bytes); bf.flip(); result.write(bf, bf, new CompletionHandler<Integer, ByteBuffer>() { public void completed(Integer a, ByteBuffer bfer) { if (bfer.hasRemaining()) { result.write(bfer, bfer, this); } } public void failed(Throwable exc, ByteBuffer attachment) { try { result.close(); } catch (IOException e) { e.printStackTrace(); } } }); } public void failed(Throwable exc, ByteBuffer attachment) { try { socketChannel.close(); } catch (IOException e) { e.printStackTrace(); } } }); } public void failed(Throwable exc, AIOServer attachment) { try { serverSocketChannel.close(); countDownLatch.countDown(); } catch (IOException e) { e.printStackTrace(); } } }); } public static void main(String[] args) throws IOException { new AIOServer().go(); }}
Netty
public class NettyServer { private static EventLoopGroup bosses = new NioEventLoopGroup(); private static EventLoopGroup workers = new NioEventLoopGroup(); public static void main(String[] args) { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bosses, workers).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new ChannelHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf bf = (ByteBuf) msg; byte[] bs = new byte[bf.readableBytes()]; bf.readBytes(bs); String recive_msg = new String(bs, "utf-8"); System.out.println(recive_msg); String rep = "get time".equals(recive_msg) ? new Date().toString() : "bad time"; ByteBuf byteBuf = Unpooled.copiedBuffer(rep.getBytes("utf-8")); ctx.writeAndFlush(byteBuf); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }); } }); try { ChannelFuture sync = bootstrap.bind(8080).sync(); sync.channel().closeFuture().sync(); } catch (Exception e) { bosses.shutdownGracefully(); workers.shutdownGracefully(); } }}
阅读全文
0 0
- Netty浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty 之 浅析ByteToMessageDecoder
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- Netty实现原理浅析
- netty源码浅析--accept
- 浅析 Netty心跳机制
- Netty实现原理浅析
- spark 编译安装
- tomcat6-源码分析(2)
- mysql的event schedule 可以让你设置你的mysql数据库再某段时间执行你想要的动作【mysql事件调度器】
- ICSE 2017 Do Developers Read Compiler Error Messages? 阅读笔记
- H5PostMessages实现跨页面通信
- Netty浅析
- 第八章El表达式第五节el表达式集合操作
- jQuery学习笔记
- 根据月份运算天数
- MVP post请求
- 制作HTML5游戏2.0
- 《HTML之列表标签》
- a/b输出商数Q和余数R 先除a 后余a string 每个字符 ---'0' 变成 int 形
- 神经网络与深度学习第二周-2-Logistic Regression with a Neural Network mindset