一、内容
1、阻塞和非阻塞是什么?
2、传统IO模型,他存在哪些阻塞点
3、NIO模型
4、对比总结
1、阻塞和非阻塞是什么?
阻塞:做某件事情,直到完成,除非超时,如果没有完成,继续等待。
非阻塞:做一件事情,尝试着做,如果说不能做完,就不做了。意思就是直接返回,如果能做完,就做。
2、传统IO模型,他存在哪些阻塞点
1) 传统IO:Socket编程 参考:Android 网络编程 Socket
2) 阻塞点:
1> Socket socket = serverSocket.accept();
2> int data = is.read(b);
缺点:如下图的,
客户: socket
大门: ServerSocket(port)
服务器: Thread
每个服务员服务一个客户,高并发下会出现很多线程。
优点:
2) NIO
增加了一个重要的角色(Selector),主要负责调度和监控客户端和服务端(调度器)
由阻塞方式改成了非阻塞(non-blocking)
阻塞点
this.selector.select();
真正关系的阻塞点是: 读取数据
3、NIO例子
/** * NIO Socket */ public class NioSocketDemo { private Selector selector; //通道选择器(管理器) public static void main(String[] args) throws IOException { NioSocketDemo nio = new NioSocketDemo(); nio.initServer(8888); nio.listenSelector(); } public void initServer(int port) throws IOException{ ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //设置非阻塞 serverSocketChannel.configureBlocking(false); serverSocketChannel.socket().bind(new InetSocketAddress(port)); this.selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("服务已启动"); } public void listenSelector() throws IOException{ //轮询监听selector while (true) { //等待客户连接 // select 模型,多路复用 this.selector.select(); Iterator<SelectionKey> iteKey = this.selector.selectedKeys().iterator(); while (iteKey.hasNext()) { SelectionKey key = iteKey.next(); iteKey.remove(); //处理请求 handler(key); } } } /** * 处理客户端请求 * @param key * @throws IOException */ private void handler(SelectionKey key) throws IOException { if(key.isAcceptable()){ //处理客户端连接请求事件 ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel(); SocketChannel socketChannel = serverSocketChannel.accept(); //设置非阻塞 socketChannel.configureBlocking(false); //接收客户端发送的信息,需要给通道设置读的权限 socketChannel.register(selector, SelectionKey.OP_READ); }else if (key.isReadable()){ //处理读的事件 SocketChannel socketChannel = (SocketChannel)key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int readData = socketChannel.read(buffer); if(readData > 0){ String info = new String(buffer.array(), "GBK").trim(); System.out.println("服务端收到数据:" + info); }else { System.out.println("客户端关闭了..."); key.cancel(); } } } }
启动Demo
启动客户端
打开CMD,
按住Ctrl + ] 进入
输入send hello world
发出send hello world后,服务端将收到数据: hello world
4、总结
传统IO