Java NIO - ตัวเลือก

ดังที่เราทราบว่า Java NIO รองรับการทำธุรกรรมหลายรายการจากและไปยังช่องและบัฟเฟอร์ดังนั้นเพื่อตรวจสอบ NIO Channel หนึ่งช่องหรือมากกว่าและพิจารณาว่าช่องทางใดที่พร้อมสำหรับการทำธุรกรรมข้อมูลเช่นการอ่านหรือการเขียน Java NIO ให้ Selector

ด้วย Selector เราสามารถสร้างเธรดเพื่อให้ทราบว่าช่องใดที่พร้อมสำหรับการเขียนและอ่านข้อมูลและสามารถจัดการกับช่องนั้น ๆ ได้

เราสามารถรับอินสแตนซ์ตัวเลือกได้โดยเรียกวิธีการคงที่ open()หลังจากเปิดตัวเลือกเราจะต้องลงทะเบียนช่องโหมดที่ไม่ปิดกั้นซึ่งจะส่งคืนอินสแตนซ์ของ SelectionKey

SelectionKey เป็นชุดของการดำเนินการที่สามารถดำเนินการกับช่องสัญญาณหรือเราสามารถพูดได้ว่าเราสามารถทราบสถานะของช่องได้โดยใช้ปุ่มการเลือก

การดำเนินการหลักหรือสถานะของช่องที่แสดงโดยปุ่มเลือกคือ -

  • SelectionKey.OP_CONNECT - ช่องที่พร้อมเชื่อมต่อกับเซิร์ฟเวอร์

  • SelectionKey.OP_ACCEPT - ช่องที่พร้อมรับการเชื่อมต่อที่เข้ามา

  • SelectionKey.OP_READ - ช่องที่พร้อมสำหรับการอ่านข้อมูล

  • SelectionKey.OP_WRITE - ช่องที่พร้อมสำหรับการเขียนข้อมูล

คีย์การเลือกที่ได้รับหลังจากการลงทะเบียนมีวิธีการที่สำคัญดังต่อไปนี้ -

  • attach() - วิธีนี้ใช้เพื่อแนบวัตถุด้วยกุญแจจุดประสงค์หลักของการแนบวัตถุเข้ากับช่องสัญญาณคือการรับรู้ช่องสัญญาณเดียวกัน

  • attachment() - วิธีนี้ใช้เพื่อเก็บวัตถุที่แนบมาจากช่องสัญญาณ

  • channel() - วิธีนี้ใช้เพื่อรับช่องสำหรับสร้างคีย์เฉพาะ

  • selector() - วิธีนี้ใช้เพื่อรับตัวเลือกที่สร้างคีย์เฉพาะ

  • isValid() - วิธีนี้คืนสภาพอากาศว่าคีย์ถูกต้องหรือไม่

  • isReadable() - วิธีนี้ระบุว่าช่องของคีย์สภาพอากาศพร้อมสำหรับการอ่านหรือไม่

  • isWritable() - วิธีนี้ระบุว่าช่องของคีย์สภาพอากาศพร้อมสำหรับการเขียนหรือไม่

  • isAcceptable() - วิธีนี้ระบุว่าช่องของคีย์สภาพอากาศพร้อมสำหรับการรับการเชื่อมต่อที่เข้ามาหรือไม่

  • isConnectable() - วิธีนี้จะทดสอบว่าแชนเนลของคีย์นี้เสร็จสิ้นหรือล้มเหลวในการดำเนินการเชื่อมต่อซ็อกเก็ต

  • isAcceptable() - วิธีนี้จะทดสอบว่าช่องของคีย์นี้พร้อมที่จะรับการเชื่อมต่อซ็อกเก็ตใหม่หรือไม่

  • interestOps() - วิธีนี้จะดึงชุดดอกเบี้ยของคีย์นี้

  • readyOps() - วิธีนี้จะดึงข้อมูลชุดที่พร้อมซึ่งเป็นชุดการดำเนินการที่ช่องพร้อมใช้งาน

เราสามารถเลือกช่องจากตัวเลือกโดยเรียกวิธีการคงที่ select()วิธีการเลือกของตัวเลือกมีมากเกินไปเนื่องจาก -

  • select() - วิธีนี้จะบล็อกเธรดปัจจุบันจนกว่าอย่างน้อยหนึ่งแชนเนลจะพร้อมสำหรับเหตุการณ์ที่ลงทะเบียนไว้

  • select(long timeout) - วิธีนี้ทำเช่นเดียวกับ select () ยกเว้นว่าจะบล็อกเธรดเป็นเวลาสูงสุดมิลลิวินาทีการหมดเวลา (พารามิเตอร์)

  • selectNow() - วิธีนี้ไม่ได้ปิดกั้นเลย แต่จะส่งคืนทันทีเมื่อมีช่องใดก็ตามที่พร้อม

นอกจากนี้เพื่อที่จะออกจากเธรดที่ถูกบล็อกซึ่งเรียกใช้วิธีการเลือกwakeup() สามารถเรียกวิธีการจากอินสแตนซ์ตัวเลือกหลังจากนั้นเธรดที่รออยู่ภายใน select () จะกลับมาทันที

ในที่สุดเราสามารถปิดตัวเลือกโดยการโทร close() ซึ่งยังทำให้อินสแตนซ์ SelectionKey ทั้งหมดที่ลงทะเบียนกับ Selector นี้ไม่ถูกต้องพร้อมกับปิดตัวเลือก

ตัวอย่าง

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SelectorDemo {
   public static void main(String[] args) throws IOException {
      String demo_text = "This is a demo String";	
      Selector selector = Selector.open();
      ServerSocketChannel serverSocket = ServerSocketChannel.open();
      serverSocket.bind(new InetSocketAddress("localhost", 5454));
      serverSocket.configureBlocking(false);
      serverSocket.register(selector, SelectionKey.OP_ACCEPT);
      ByteBuffer buffer = ByteBuffer.allocate(256);
      while (true) {
         selector.select();
         Set<SelectionKey> selectedKeys = selector.selectedKeys();
         Iterator<SelectionKey> iter = selectedKeys.iterator();
         while (iter.hasNext()) {
            SelectionKey key = iter.next();
            int interestOps = key.interestOps();
            System.out.println(interestOps);
            if (key.isAcceptable()) {
               SocketChannel client = serverSocket.accept();
               client.configureBlocking(false);
               client.register(selector, SelectionKey.OP_READ);
            }
            if (key.isReadable()) {
               SocketChannel client = (SocketChannel) key.channel();
               client.read(buffer);
               if (new String(buffer.array()).trim().equals(demo_text)) {
                  client.close();
                  System.out.println("Not accepting client messages anymore");
               }
               buffer.flip();
               client.write(buffer);
               buffer.clear();
            }
            iter.remove();
         }
      }
   }
}