高性能网络编程之IO和NIO阻塞分析

一、内容

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

原文地址:https://www.cnblogs.com/linlf03/p/10463132.html