NON BLOCKING IO LÀ GÌ

  -  
Tổng quan

Khi Client gửi một request tới Server thì bên Server sẽ tiếp nhận làm việc với dữ liệu trong request và gửi lại response cho Client. Để có thể thực hiện được điều này thì cả Server và Client phải kết nối tới một thành phần trung gian gọi là Socket. Khi cả client và server tạo mối liên kết tới Socket thì khi đó server sẽ lắng nghe thông qua socket để có thể tiếp nhận request từ client.Có thể hiểu về cơ chế hoạt động như hình bên dưới


Bạn đang xem: Non blocking io là gì

*

Sau khi kết nối được tạo ra lúc này cả server và client để đọc và ghi dữ liệu thông qua socket mà đã được liên kết đó.

Blocking IO

Trong trường hợp này khi một client gửi một request tới server thì khi đó luồng xử lý dữ liệu cho liên kết giữa client và server sẽ bị khóa lại cho đến khi nào request đó được thực hiện xong hoàn toàn (chẳng hạn như lấy data từ database thì phải có dữ liệu trả về, hoặc thêm sửa xóa dữ liệu thì cũng phải có phản hồi trả về cho việc hoàn thành công việc từ phía server). Trong thời gian này nếu có một request khác được gửi đến server thì bắt buộc phải chờ cho đến khi tác vụ trước đó được hoàn thành. Việc xử lý cho trường hợp có nhiều request gửi tới server thì cũng khá tốn kém. Trước tiên ứng với mỗi request thì cần phải tạo ra một luồng riêng cho request đó, nếu luồng đó tới sau một luỗng dữ liệu khác thì nó bắt buộc phải chờ cho tới lượt.Các bước mô tả cho hoạt động của Blocking IO được mô tả như sau

Trước tiên cần tạo ra một Server Socket tương ứng với cổng của server đó để lắng nghe và tiếp nhận request

ServerSocket serverSocket = new ServerSocket(portNumber);Sau khi tạo server socket tương ứng với cổng server chúng ta có một socket để có thể lắng nghe request từ client như sau

*

Bây giờ chúng ta gọi hàm accept() để server bắt đầu chờ client tạo kết nối, và khi client tạo một request thì nó sẽ chấp nhận và return về một socket để tương tác với client


Xem thêm: Cùng Nhìn Lại Bong Bóng Dot Com Cách Đây 15 Năm, Bong Bóng Dotcom 2000

*

*

Sau khi đã hoàn tất việc kết nối thì chúng ta có để đọc ghi dữ liệu thông qua soket được tạo ra đó

BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));PrintWriter out =new PrintWriter(clientSocket.getOutputStream(), true);Trường hợp nhiều request tới thì chúng ta có thể xem như thế này


Xem thêm: Mô Hình Sóng Elliott Điều Chỉnh, Hướng Dẫn Cách Giao Dịch Theo Sóng Elliott

*

Một số nhược điển của phương thức này như sau

Mỗi luồng xử lý dữ liệu của từng request yêu cầu cấp bộ nhớ stack cho nó, cho nên việc có nhiều luồng như vậy sẽ chiếm rất nhiều bộ nhớ, khiến nó trở nên cồng kềnh và khó khăn trong việc chuyển đổi qua lại giữa các luồng.Ở mỗi thời điểm thì chỉ có mỗi một luồng được xử lý còn tất cả các luồng còn lại phải chờ, điều này làm cho lãng phí bộ nhớ không cần thiết khi mà chúng ta phải cấp quá nhiều bộ nhớ cho việc đứng chờ như vậy.Non Blocking IOMột số bước để tạo một NIO đơn giản

Tạo một selector để xử lý nhiều kênh và đồng thời để cho phép server có thể tìm tất cả các liên kết mà đã sẵn sãng cho việc nhận output và gửi input

Selector selector = Selector.open();Tạo một server socket channel để có thể chấp nhận kết nối mớiServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.configureBlocking(false)Sau đó chúng ta có thể liên kết server socket channek với host và post của serverInetSocketAddress hostAddress = new InetSocketAddress(hostname, portNumber);serverChannel.bind(hostAddress);Bây giờ chúng ta cần đăng ký server socket channel này với selector và "SelectionKey.OP_ACCEPT" tham số để thông báo cho selector để lắng nghe tới kết nối mới. "OP_ACCEPT" có thể hiểu rằng server socket channel đã sẵn sàng để chấp nhận kết nối mới từ client.serverChannel.register(selector, SelectionKey.OP_ACCEPT);Chúng ta dùng hàm select() của selector để đếm số lượng channel mà đã có để tương tácwhile (true) { int readyCount = selector.select(); if (readyCount == 0) { continue; } // process selected keys...}Trong trường hợp selector tìm thấy một channel đã sẵn sàng , hàm selectedKeys() trả về tập hợp các key mà đã sẵn sàng, tương ững mỗi key cho mỗi channel mà chúng ta có thể tương tác// process selected keys...Set readyKeys = selector.selectedKeys();Iterator iterator = readyKeys.iterator();while (iterator.hasNext()) { SelectionKey key = iterator.next(); // Remove key from set so we don"t process it twice iterator.remove(); // operate on the channel...}Nếu key mà acceptable thì có nghĩa là client yêu cầu một kết nối// operate on the channel... // client requires a connection if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel(); // get client socket channel SocketChannel client = server.accept(); // Non Blocking I/O client.configureBlocking(false); // record it for read/write operations (Here we have used it for read) client.register(selector, SelectionKey.OP_READ); continue; }Nếu key là readable thì chúng ta có thể đọc data từ client// if readable then the server is ready to read if (key.isReadable()) { SocketChannel client = (SocketChannel) key.channel(); // Read byte coming from the client int BUFFER_SIZE = 1024; ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); try { client.read(buffer); } catch (Exception e) { // client is no longer active e.printStackTrace(); continue; }Nếu key là writable thì có nghĩa là server đã sẵn sàng để gửi dữ liệu lại cho clientif (key.isWritable()) { SocketChannel client = (SocketChannel) key.channel(); // write data to client...}Bây giờ chúng ta cần tạo ra một client đơn giản để kết nối tới server

Trước tiên cần tạo ra một socket channel để kết nối tới server (với host và port của server đó)

SocketAddress address = new InetSocketAddress(hostname, portnumber);SocketChannel client = SocketChannel.open(address);Bây giờ thay vì dùng tới socket input và output stream thì chúng ta sẽ ghi data vào chính channel. Đương nhiên trước khi ghi thì chúng ta cần encode dạng ByteBuffer như đã đề cập phía trên.ByteBuffer buffer = ByteBuffer.allocate(74);buffer.put(msg.getBytes());buffer.flip();client.write(buffer);Tài liệu tham khảohttps://www.baeldung.com/java-nio-selectorhttps://docs.oracle.com/javase/tutorial/networking/sockets/definition.htmlhttps://medium.com/coderscorner/tale-of-client-server-and-socket-a6ef54a74763