转载

Netty源码01-Java的NIO(二)

Channel 通道

通道表示到实体(如硬件设备、文件、网络套接字或程序组件)的开放连接,该实体能够执行一个或多个不同的I/O操作,例如读取或写入

FileChannel

  • 用于读取、写入、映射和操作文件的通道
  • 文件通道是连接到文件的 SeekableByteChannel 。它在其文件中有一个当前的 position ,可以是查询 position ,也可以是修改的 position(long) 。文件本身包含一个可变长度的字节序列,可以读取和写入,并且可以查询当前的 size 。当写入的字节超过当前大小时,文件大小会增加;当文件 truncated 时,文件大小会减小。文件还可能具有一些关联的元数据,例如访问权限、内容类型和上次修改时间;此类不定义元数据访问的方法。

FileChannel的类继承关系:

Netty源码01-Java的NIO(二)

  • FileChannel的读写分离体现了接口的隔离原则
  • FileChannel中的read函数根据 直接或非直接 ByteBuffer读取到堆缓冲区或者直接返回buffer缓冲区

SocketChannel

  • 网络套接字Socket和上面文件是一样的,在Linux上都抽象成了 文件描述符fd
  • SocketChannel面向流的连接套接字的可选通道
  • 通过调用此类的 open 方法创建套接字通道。无法为任意的、预先存在的套接字创建通道。新创建的套接字通道已打开,但尚未连接。试图在未连接的通道上调用I/O操作将导致引发 NotYetConnectedException 。套接字通道可以通过调用其 connect 方法进行连接;一旦连接,套接字通道将保持连接,直到关闭。套接字通道是否连接可以通过调用其 isConnected 方法来确定
  • SocketChannel支持 无阻塞连接

SocketChannel的类继承关系:

Netty源码01-Java的NIO(二)

Selector

  • Selector是SelectableChannel对象的多路复用选择器
  • 可以通过调用此类的 open 方法来创建选择器,该方法将使用系统默认的 java.nio.channels.spi.SelectorProvider 选择器来创建新的选择器。还可以通过调用自定义选择器 java.nio.channels.spi.SelectorProvider.openSelector 方法来创建选择器。选择器保持打开状态,直到通过其 close 方法关闭为止
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);

使用Selector的Java NIO示例代码

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress("127.0.0.1", 8888));
        ssc.configureBlocking(false);

        System.out.println("server started, listening on :" + ssc.getLocalAddress());
        Selector selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);

        while(true) {
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> it = keys.iterator();
            while(it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();
                handle(key);
            }
        }

    }

    private static void handle(SelectionKey key) {
        if(key.isAcceptable()) {
            try {
                ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                SocketChannel sc = ssc.accept();
                sc.configureBlocking(false);
                //new Client
                //
                //String hostIP = ((InetSocketAddress)sc.getRemoteAddress()).getHostString();

            /*
            log.info("client " + hostIP + " trying  to connect");
            for(int i=0; i<clients.size(); i++) {
                String clientHostIP = clients.get(i).clientAddress.getHostString();
                if(hostIP.equals(clientHostIP)) {
                    log.info("this client has already connected! is he alvie " + clients.get(i).live);
                    sc.close();
                    return;
                }
            }*/

                sc.register(key.selector(), SelectionKey.OP_READ );
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
        } else if (key.isReadable()) { //flip
            SocketChannel sc = null;
            try {
                sc = (SocketChannel)key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(512);
                buffer.clear();
                int len = sc.read(buffer);

                if(len != -1) {
                    System.out.println(new String(buffer.array(), 0, len));
                }

                ByteBuffer bufferToWrite = ByteBuffer.wrap("HelloClient".getBytes());
                sc.write(bufferToWrite);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(sc != null) {
                    try {
                        sc.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
原文  https://segmentfault.com/a/1190000022097365
正文到此结束
Loading...