Netty :
一个用来做sokect网络编程的高性能框架;
一个替代JDK NIO的优秀框架;
是大多数高并发/分布式框架的底层基础;
目录:
[TOC]
参考:基础介绍 https://www.jianshu.com/p/a4e03835921a
传统IO编程如何做c/s通信
IOServer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| package mxx.netty.io;
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;
public class IOServer { public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8000);
new Thread(() -> { while (true) { try { Socket socket = serverSocket.accept();
new Thread(() -> { try { String tName = Thread.currentThread().getName();
byte[] data = new byte[1024]; InputStream inputStream = socket.getInputStream(); while (true) { int len; while ((len = inputStream.read(data)) != -1) { System.out.println(tName + '-' +new String(data, 0, len)); } } } catch (IOException e) { } }).start();
} catch (IOException e) { }
} }).start(); } }
|
IOClient
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package mxx.netty.io;
import java.io.IOException; import java.net.Socket; import java.util.Date;
public class IOClient {
public static void main(String[] args) { new Thread(() -> { try { Socket socket = new Socket("127.0.0.1", 8000); while (true) { try { socket.getOutputStream().write((new Date() + ": hello world").getBytes()); socket.getOutputStream().flush(); Thread.sleep(2000); } catch (Exception e) { } } } catch (IOException e) { } }).start(); } }
|
NIO编程 vs IO编程
IO编程问题:
1、1w个client连接对应server要开1w个线程去维护,继而1w个while死循环
2、线程资源受限:大量线程阻塞,操作系统耗不起
3、线程切换效率低下:要在1w个线程里来回切
4、数据读写是以字节流为单位,效率不高
如何解决以上问题的?
1、线程资源受限
新连接不再创建线程,而是批量绑定。
一个循环如何监测1w个连接?
selector:新连接注册到selector上,批量监测出有数据可读的连接(同一时刻只有少量的连接有数据可读)
实际开发中,会开多个线程,每个线程都管理着一批连接,这样线程消耗大幅减少。
2、线程切换效率低下
NIO模型中线程数量大大降低,线程切换效率因此也大幅度提高
3、IO读写以字节为单位
NIO以字节块为单位读取,NIO维护一个缓冲区。
使用JDK原生NIO实现server
强烈不建议直接基于JDK原生NIO来进行网络开发
(看看注释就行了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| package mxx.netty.m02_jdk_nio;
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Iterator; import java.util.Set;
public class NIOServer { public static void main(String[] args) throws IOException { Selector serverSelector = Selector.open(); Selector clientSelector = Selector.open();
new Thread(() -> { try { ServerSocketChannel listenerChannel = ServerSocketChannel.open(); listenerChannel.socket().bind(new InetSocketAddress(8000)); listenerChannel.configureBlocking(false); listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
while (true) { if (serverSelector.select(1) > 0) { Set<SelectionKey> set = serverSelector.selectedKeys(); Iterator<SelectionKey> keyIterator = set.iterator();
while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next();
if (key.isAcceptable()) { try { SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept(); clientChannel.configureBlocking(false); clientChannel.register(clientSelector, SelectionKey.OP_READ); } finally { keyIterator.remove(); } }
} } } } catch (IOException ignored) { }
}).start();
new Thread(() -> { try { while (true) { if (clientSelector.select(1) > 0) { Set<SelectionKey> set = clientSelector.selectedKeys(); Iterator<SelectionKey> keyIterator = set.iterator();
while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next();
if (key.isReadable()) { try { SocketChannel clientChannel = (SocketChannel) key.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); clientChannel.read(byteBuffer); byteBuffer.flip(); System.out.println(Charset.defaultCharset().newDecoder().decode(byteBuffer) .toString()); } finally { keyIterator.remove(); key.interestOps(SelectionKey.OP_READ); } }
} } } } catch (IOException ignored) { } }).start();
} }
|
Netty编程
概述:
1、Netty封装了JDK的NIO,用户友好
2、官话:”Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务器和客户端。”
使用Netty不使用JDK原生NIO的原因:
1、JDK-NIO:使用复杂、BUG横飞
2、Netty底层IO模型随意切换(可以直接从NIO模型变身为IO模型)
3、简化开发,脱离细节,专注业务(Netty自带的拆包解包,异常检测等机制…)
4、Netty解决了JDK的很多BUG
5、Netty底层对线程,selector做了很多细小的优化
6、自带各种协议栈
7、Netty社区活跃
8、Netty已经历各大rpc框架,消息中间件,分布式通信中间件线上的广泛验证,健壮性无比强大
开始写代码…
maven
1 2 3 4 5
| <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.6.Final</version> </dependency>
|
END
下一步:一个Netty实战项目