non-blocking I/O 和 blocking I/O 区别

在应用中,客户端连接到服务端,服务器处理请求并响应。在这个过程中,客户端和服务端通过socket连接,绑定到socket中,服务端等待着监听来自client的请求。
non-blocking I/O 和 blocking I/O 区别_第1张图片

客户端与服务端连接后,相互读写数据通过socket。

Blocking I/O – 堵塞 I/O

通过Blocking I/O,客户端发送请求到服务端,线程处理这个连接,这是一个堵塞,直到数据读取或者写入完成。相关操作在完成之前,线程都是一直等待。现在执行一个并发请求,这就是需要多线程,需要分配新的线程

  • 先创建 server socket 监听请求连接通过指定端口
ServerSocket serverSocket = new ServerSocket(portNumber);

non-blocking I/O 和 blocking I/O 区别_第2张图片

Server Socket 监听客户端连接

  • 调用accept() 方法,服务端启动并等待客户端连接,当客户端发送请求时,server socket 接收来自客户端的请求并用 新的socket与客户端连接,在新的连接之前,server socket 是堵塞的,
Socket clientSocket = serverSocket.accept();

non-blocking I/O 和 blocking I/O 区别_第3张图片non-blocking I/O 和 blocking I/O 区别_第4张图片

  • 现在可以从socket 读取和写入streams了
BufferReader in = new BufferReader(new InputStreamReader(clientSocket.getInputStream()));

PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
  • 这时我们就可以读取来自input stream中的每行数据,处理并通过output stream响应给客户端
String request, response;
while ((request = in.readLine()) != null) {
	response = processRequest(request);
	out.println(response);
	if ("Done".equals(request)) {
		break;
	}
}

现在处于连接时刻,处理并发用户,服务端就需要分配新的线程给每个客户端socket

while (listening) {
	接收 连接;
	创建新的线程给客户端;
}

non-blocking I/O 和 blocking I/O 区别_第5张图片

不利

  • 每个线程都必须在内存推栈中分配,增加连接数量,大量线程切换就成为很笨重
  • 多线程等待客户端的请求,这就是在浪费资源

因此,当考虑大量用户的时候,blocking I/O就无能为力了。

Non-blocking I/O – 非阻塞 IO

使用non-blocking I/O,可以使用单线程处理多并发的连接,在继续往下讲的时候,需要解释下专业词汇。

  • 在NIO中,读写数据是buffer,不是stream。
  • “channel” 读取和写入TCP socket,数据必须编码成ByteBuffer对象
  • “Readiness Selection” 意味着,在读写中选择 socket。

non-blocking I/O 和 blocking I/O 区别_第6张图片

  • 创建selector 处理多个 channels
Selector selector = Selector.open();
  • 在non blocking 创建 一个 server socket channel “ServerSocketChannel” 代表接收新的连接
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
  • 我们绑定server socket channel 到特定的端口
InetSocketAddress hostAddress = new InetSocketAddress(hostname, portNumber);
 
serverChannel.bind(hostAddress);
  • 现在注册server socket channel 通过 selector 和 “SelectionnKey.OP_ACCEPT” 参数 告诉“selector“ 监听进来的连接。
serverChannel.register(selector, SelectionnKey.OP_ACCEPT);

你可能感兴趣的:(并发)