Netty知识总结

 

 

Netty知识总结

一:各组件及其作用

1.selector: 要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

2.channel: Channel的实现

这些是Java NIO中最重要的通道的实现:

•    FileChannel

•    DatagramChannel

•    SocketChannel

•    ServerSocketChannel

FileChannel 从文件中读写数据。

DatagramChannel 能通过UDP读写网络中的数据。

SocketChannel 能通过TCP读写网络中的数据。

ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

基本的 Channel 示例

下面是一个使用FileChannel读取数据到Buffer中的示例:

01  RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");

02  FileChannel inChannel = aFile.getChannel();

03 

04  ByteBuffer buf = ByteBuffer.allocate(48);

05 

06  int bytesRead = inChannel.read(buf);

07  while (bytesRead != -1) {

08 

09  System.out.println("Read " + bytesRead);

10  buf.flip();

11 

12  while(buf.hasRemaining()){

13  System.out.print((char) buf.get());

14  }

15 

16  buf.clear();

17  bytesRead = inChannel.read(buf);

18  }

19  aFile.close();

注意 buf.flip() 的调用,首先读取数据到Buffer,然后反转Buffer,接着再从Buffer中读取数据

3. Buffer的类型

Java NIO 有以下Buffer类型

•    ByteBuffer

•    MappedByteBuffer

•    CharBuffer

•    DoubleBuffer

•    FloatBuffer

•    IntBuffer

•    LongBuffer

•    ShortBuffer

 

二:模拟客户端与服务器端的通信

服务器端:

package selector;

 

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.util.Iterator;

import java.util.Set;

 

public class WebServer {

    public static void main(String[] args) {

        try {

            ServerSocketChannel ssc = ServerSocketChannel.open();

            ssc.socket().bind(new InetSocketAddress("127.0.0.1", 8000));

            ssc.configureBlocking(false);

 

            Selector selector = Selector.open();

            // 注册 channel,并且指定感兴趣的事件是 Accept

            ssc.register(selector, SelectionKey.OP_ACCEPT);

 

            ByteBuffer readBuff = ByteBuffer.allocate(1024);

            ByteBuffer writeBuff = ByteBuffer.allocate(128);

            writeBuff.put("received".getBytes());

            writeBuff.flip();

 

            while (true) {

                int nReady = selector.select();

                Set<SelectionKey> keys = selector.selectedKeys();

                Iterator<SelectionKey> it = keys.iterator();

 

                while (it.hasNext()) {

                    SelectionKey key = it.next();

                    it.remove();

 

                    if (key.isAcceptable()) {

                        // 创建新的连接,并且把连接注册到selector上,而且,

                        // 声明这个channel只对读操作感兴趣。

                        SocketChannel socketChannel = ssc.accept();

                        socketChannel.configureBlocking(false);

                        socketChannel.register(selector, SelectionKey.OP_READ);

                    }

                    else if (key.isReadable()) {

                        SocketChannel socketChannel = (SocketChannel) key.channel();

                        readBuff.clear();

                        socketChannel.read(readBuff);

 

                        readBuff.flip();

                        System.out.println("received : " + new String(readBuff.array()));

                        key.interestOps(SelectionKey.OP_WRITE);

                    }

                    else if (key.isWritable()) {

                        writeBuff.rewind();

                        SocketChannel socketChannel = (SocketChannel) key.channel();

                        socketChannel.write(writeBuff);

                        key.interestOps(SelectionKey.OP_READ);

                    }

                }

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}

 

 

客户端:

package selector;

 

import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SocketChannel;

 

public class WebClient {

    public static void main(String[] args) throws IOException {

        try {

            SocketChannel socketChannel = SocketChannel.open();

            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8000));

 

            ByteBuffer writeBuffer = ByteBuffer.allocate(32);

            ByteBuffer readBuffer = ByteBuffer.allocate(32);

 

            writeBuffer.put("hello".getBytes());

            writeBuffer.flip();

 

            while (true) {

                writeBuffer.rewind();

                socketChannel.write(writeBuffer);

                readBuffer.clear();

                socketChannel.read(readBuffer);

            }

        } catch (IOException e) {

        }

    }

}

 

 

Netty知识总结

 

 

三:

mmap sendFile 的区别。

  1. mmap 适合小数据量读写(RockctMQ)sendFile (Kafka)适合大文件传输。
  2. mmap是由cpu copy+DMA copy两种方式进行拷贝,sendFile是仅由DMA copy,因为没有CPU copy,所以被称之为零拷贝

 

 

 

四:netty三种线程模型

单线程模型

 

多线程模型

 

主从多线程模型