Netty原理架构解析
【硬核】肝了一月的Netty知识点
简单深入理解高性能网络编程(Netty)中的Reactor模型(图文+代码)
Netty原理浅析
分散读,集中写
阻塞模式
非阻塞模式
selector模式
public static void main(String[] args) throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(8080));
Selector selector = Selector.open();
SelectionKey sscKey = ssc.register(selector,0,null);
sscKey.interestOps(SelectionKey.OP_ACCEPT);
while (true){
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
iterator.remove();
if(key.isAcceptable()){
ServerSocketChannel channel = (ServerSocketChannel)key.channel();
SocketChannel sc = channel.accept();
sc.configureBlocking(false);
SelectionKey scKey = sc.register(selector,0,null);
scKey.interestOps(SelectionKey.OP_READ);
} else if (key.isReadable()){
try {
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(16);
int read = channel.read(buffer);
if(read==-1){
key.cancel();
} else {
buffer.flip();
}
} catch (IOException e){
key.cancel();
}
}
}
}
}
public static void main(String[] args) throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(8080));
Selector selector = Selector.open();
SelectionKey sscKey = ssc.register(selector,0,null);
sscKey.interestOps(SelectionKey.OP_ACCEPT);
while (true){
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
iterator.remove();
if(key.isAcceptable()){
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
SelectionKey scKey = sc.register(selector,SelectionKey.OP_READ,null);
//1.向客户端发送大量的数据
StringBuffer sb = new StringBuffer();
for(int i=0;i<30000;i++){
sb.append("a");
}
; ByteBuffer buffer = Charset.defaultCharset().encode(sb.toString());
int write = sc.write(buffer); //2.返回值代表实际写入字节数
if(buffer.hasRemaining()){ //3。是否有剩余
sscKey.interestOps(scKey.interestOps()|SelectionKey.OP_WRITE); //关注可写事件
sscKey.attach(buffer);//把未写完的数据挂到sscKey上
}
} else if(key.isWritable()){
ByteBuffer buffer = (ByteBuffer)key.attachment();
SocketChannel sc = (SocketChannel)key.channel();
sc.write(buffer);
if(!buffer.hasRemaining()){
key.attach(null); //清除buff
key.interestOps(key.interestOps()-SelectionKey.OP_WRITE); //无需关注可写事件
}
}
}
}
}
每个线程分配一个选择器Worker
class Worker implements Runnable {
private Thread thread;
private Selector worker;
private String name;
private volatile Boolean isStart = false;
private ConcurrentLinkedQueue<Runnable> queue = new ConcurrentLinkedQueue<>();
public Worker(String name){
this.name = name;
}
public void register(SocketChannel sc){
if(!isStart){
this.thread = new Thread(this,name);
thread.start();
isStart = true;
}
queue.add(()->{
try {
sc.register(worker,SelectionKey.OP_READ,null);
} catch (ClosedChannelException e){
}
});
worker.wakeup(); //唤醒select方法
}
@Override
public void run() {
try {
worker.select();
Runnable task = queue.poll();
if (task != null){
task.run();
}
Iterator<SelectionKey> iterator = worker.selectedKeys().iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
iterator.remove();;
if(key.isReadable()){
ByteBuffer buffer = ByteBuffer.allocate(16);
SocketChannel channel = (SocketChannel)key.channel();
channel.read(buffer);
buffer.flip();
}
}
} catch (IOException e){
}
}
}
也可以如下这种方式:
如果主线程运行的快,也就是selector.select()先执行,阻塞,然后执行selector.wakeUp()被唤醒,然后sc.register…
同理可知其他顺序亦可
Netty
服务器
public static void main(String[] args) {
new ServerBootstrap()
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioServerSocketChannel>() {
@Override
protected void initChannel(NioServerSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
}
});
}
})
.bind(8080);
}
客户端
public static void main(String[] args) throws InterruptedException {
new Bootstrap()
.group(new NioEventLoopGroup())
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
}
})
.connect(new InetSocketAddress("localhost",8080))
.sync()
.channel()
.writeAndFlush("hello,world");
}
JDK中的Future
Netty中Future
netty promise
零拷贝,,组合两个ByteBuf