
Socket建设完毕,网络数据的传输通路没问题,那么数据,该怎么读取呢?
与其说是Java的IO历史,不如说是操作系统的网络IO历史。
以Linux为例: 第一阶段:调用read读取socket数据,有数据则读取,没数据则等待。 第二阶段:调用read读取socket数据,有数据则读取,没数据则返回-1, errno设置为EAGAIN。 第三阶段:监听socket,有数据则通知。
第一阶段:调用read读取socket数据,有数据则读取,没数据则等待。 在此前提下如何设计Java程序呢:
java 代码解读复制代码public class ServerSocketDemo {
    public static void main(String[] args) throws IOException {
        // 创建一个线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        // 创建ServerSocket
        ServerSocket serverSocket = new ServerSocket(3000);
        // 死循环(监听serverSocket),等待客户端连接
        while (true) {
            Socket clientSocket = serverSocket.accept(); 
            // 创建一个线程用于处理通信数据
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    //handler方法为处理数据的方法:见下文 B)IO处理数据为代码示例
                    handler(clientSocket); 
                }
            });
        }
    }
}arduino 代码解读复制代码private static void handler(Socket clientSocket) throws IOException {
        //接收数据,没有数据可读时就阻塞
        int read = clientSocket.getInputStream().read(new byte[1024]);
        if (read != -1) {
            //处理数据的业务方法
        }
}read() 操作卡住的(阻塞),如果单线程很可能卡死住,如果多线程呢(如上),可以解决卡住问题,但是带来哪些影响?
这种调用read读取socket数据,有数据则读取,没数据则等待。称之为BIO,即阻塞IO。
第二阶段:调用read读取socket数据,有数据则读取,没数据则返回-1, errno设置为EAGAIN。
Java为此做了哪些改变呢?NIO模型登场!
对应的操作系统是什么呢?
I/O多路复用底层主要用的Linux 内核·函数(select,poll,epoll)来实现 windows不支持epoll实现,windows底层是基于winsock2的select函数实现的(不开源)
scss 代码解读复制代码public class NioServer {
    public static void main(String[] args) throws IOException, InterruptedException {
        // 创建NIO ServerSocketChannel
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        // 设置ServerSocketChannel为非阻塞
        serverSocket.configureBlocking(false);
        // 打开Selector处理Channel,即创建epoll
        Selector selector = Selector.open();
        // 把ServerSocketChannel注册到selector上,并且selector对客户端accept连接操作感兴趣
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            // 阻塞等待需要处理的事件发生
            selector.select();
            // 获取selector中注册的全部事件的 SelectionKey 实例
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            // 遍历SelectionKey对事件进行处理
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 如果是OP_ACCEPT事件,则进行连接获取和事件注册
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    // 这里只注册了读事件,如果需要给客户端发送数据可以注册写事件
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    //客户端连接成功
                // 如果是OP_READ事件,则进行读取和打印
                } else if (key.isReadable()) {  
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                    int len = socketChannel.read(byteBuffer);
                    // 如果有数据
                    if (len > 0) {
                        //接收数据
                        String data = new String(byteBuffer.array());
                        //执行处理数据的业务逻辑
                    // 如果客户端断开连接,关闭Socket
                    } else if (len == -1) { 
                        //客户端断开连接,关闭socket
                        socketChannel.close();
                    }
                }
                //从事件集合里删除本次处理的key,防止下次select重复处理
                iterator.remove();
            }
        }
    }
}NIO整个调用流程就是
事件的异步通知
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。