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();
}
}
}
}