Java NIO (New Input/Output) একটি উন্নত ইনপুট/আউটপুট API যা একাধিক চ্যানেল থেকে I/O অপারেশনগুলো সঠিকভাবে এবং দক্ষভাবে পরিচালনা করতে সক্ষম। NIO-এর একটি গুরুত্বপূর্ণ কম্পোনেন্ট হল Selector, যা একাধিক I/O চ্যানেল থেকে রেডি অপারেশনগুলো চেক করতে এবং তাদের উপর কাজ করতে সাহায্য করে। Selector এর মাধ্যমে একাধিক চ্যানেলের I/O অপারেশন একটি মাত্র থ্রেডের মাধ্যমে পরিচালনা করা যায়, যা অ্যাপ্লিকেশনকে আরও স্কেলেবল এবং কার্যকরী করে তোলে।
এখানে আমরা Selector ব্যবহার করে Multiple Channels পরিচালনার ধারণা এবং উদাহরণ দেখব।
Selector এর সাথে Multiple Channels পরিচালনা
Selector Java NIO এর একটি গুরুত্বপূর্ণ উপাদান, যা non-blocking I/O কাজগুলো পরিচালনা করতে সক্ষম। এটি একটি থ্রেড ব্যবহার করে একাধিক চ্যানেলের উপর নজর রাখতে পারে, এবং যেগুলি প্রস্তুত থাকে (যেমন, রিড বা রাইট করার জন্য প্রস্তুত), তাদের ওপর নির্দিষ্ট কাজ করতে পারে। এটি সাধারণত ServerSocketChannel এবং SocketChannel এর মতো নেটওয়ার্ক চ্যানেলগুলির জন্য ব্যবহৃত হয়, যাতে একক থ্রেড দ্বারা একাধিক ক্লায়েন্টের সাথে যোগাযোগ করা যায়।
Multiple Channels এর সাথে Selector ব্যবহারের সুবিধা
- একটি থ্রেড দিয়ে একাধিক চ্যানেল পরিচালনা: Selector ব্যবহার করে, একটি মাত্র থ্রেড একাধিক চ্যানেল থেকে ইনপুট বা আউটপুট ইভেন্ট প্রক্রিয়া করতে পারে, যা সিস্টেমের পারফরম্যান্স উন্নত করে এবং রিসোর্স ব্যবহারের দক্ষতা বৃদ্ধি করে।
- নন-ব্লকিং I/O: যখন কোনো চ্যানেল রেডি হয়, তখন তা সিলেক্ট করা হয়, অন্যথায় সিস্টেম ব্লক করা হয় না, যা অ্যাপ্লিকেশনকে দ্রুত এবং প্রতিক্রিয়া সক্ষম রাখে।
- সহজ পরিচালনা: একাধিক ক্লায়েন্টের সাথে কাজ করতে বা একাধিক নেটওয়ার্ক চ্যানেল ম্যানেজ করতে, Selector একটি সিম্পল এবং কার্যকরী উপায় সরবরাহ করে।
Selector এবং Multiple Channels পরিচালনা
১. Selector তৈরি করা
প্রথমে একটি Selector তৈরি করতে হবে যা একাধিক চ্যানেল মনিটর করবে।
Selector selector = Selector.open(); // Create a new Selector
২. চ্যানেল রেজিস্টার করা
নতুন একটি ServerSocketChannel অথবা SocketChannel তৈরি করে এবং সেগুলি Selector এর কাছে রেজিস্টার করা হবে।
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false); // Set to non-blocking mode
serverChannel.bind(new InetSocketAddress(8080)); // Bind to a port
serverChannel.register(selector, SelectionKey.OP_ACCEPT); // Register channel with selector for ACCEPT operation
এখানে, ServerSocketChannel-এর মাধ্যমে ক্লায়েন্টদের কানেকশন অ্যাকসেপ্ট করা হবে এবং এটি OP_ACCEPT অপারেশন জন্য রেজিস্টার করা হয়েছে।
৩. Selector তে সিলেক্ট করা
selector.select() মেথড ব্যবহার করে আপনি নির্বাচন করবেন কোন চ্যানেল প্রস্তুত হয়েছে। এটি একটি ব্লকিং মেথড, যা শুধুমাত্র তখনই ফিরে আসবে যখন কোন চ্যানেল প্রস্তুত হবে।
int readyChannels = selector.select(); // Block until at least one channel is ready
৪. চ্যানেলগুলি প্রক্রিয়া করা
selectedKeys() ব্যবহার করে আপনি সিলেক্টেড চ্যানেলগুলো থেকে কী ধারণ করতে পারেন এবং তারপর সেগুলির উপর কাজ করতে পারেন (যেমন, রিড বা রাইট অপারেশন)।
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove(); // Remove the current key from the set
if (key.isAcceptable()) {
// Accept new client connection
ServerSocketChannel serverSocket = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverSocket.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// Read data from client
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(256);
clientChannel.read(buffer);
buffer.flip();
System.out.println("Received data: " + new String(buffer.array()));
}
}
এই কোডটি সিলেক্টেড চ্যানেলগুলির উপর বিভিন্ন I/O অপারেশন যেমন accept, read, ইত্যাদি সম্পাদন করবে। যেমন যদি OP_ACCEPT অপারেশন প্রস্তুত থাকে, এটি নতুন ক্লায়েন্টের সাথে কানেকশন গ্রহণ করবে এবং তারপর OP_READ এর জন্য চ্যানেলটি রেজিস্টার করবে।
৫. চ্যানেলগুলির উপর কাজ করা
যতবার একটি চ্যানেল প্রস্তুত হয়, আপনি তার উপর প্রয়োজনীয় অপারেশন করতে পারেন, যেমন ডেটা পাঠানো বা গ্রহণ করা। উপরে দেওয়া কোডের মতো, আপনি SelectionKey.isReadable() এবং SelectionKey.isWritable() পদ্ধতি ব্যবহার করে চ্যানেল থেকে ডেটা পড়তে বা লিখতে পারেন।
উদাহরণ: Multiple Clients এর সাথে Server-Client যোগাযোগ
এখানে একটি সাধারন উদাহরণ দেখানো হচ্ছে, যেখানে একটি ServerSocketChannel একাধিক SocketChannel এর সাথে যোগাযোগ পরিচালনা করছে।
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
public class MultiChannelServer {
public static void main(String[] args) throws IOException {
// Create the server channel
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(8080));
// Create the selector
Selector selector = Selector.open();
// Register the server channel with the selector
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started...");
while (true) {
// Select ready channels
int readyChannels = selector.select();
if (readyChannels == 0) continue;
// Get the selected keys
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (key.isAcceptable()) {
// Accept client connection
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = server.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Client connected: " + clientChannel.getRemoteAddress());
} else if (key.isReadable()) {
// Read data from client
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(256);
int bytesRead = clientChannel.read(buffer);
if (bytesRead == -1) {
clientChannel.close();
} else {
buffer.flip();
System.out.println("Received data: " + new String(buffer.array()));
}
}
}
}
}
}
এই কোডটি একটি সিঙ্গেল থ্রেডে একাধিক ক্লায়েন্টের সাথে সংযোগ স্থাপন এবং ডেটা পাঠানোর জন্য Selector ব্যবহার করছে। ক্লায়েন্টের কানেকশন OP_ACCEPT এর মাধ্যমে গ্রহণ করা হচ্ছে এবং এরপর OP_READ রেজিস্টার করা হচ্ছে, যাতে ডেটা পড়া যায়।
Selector Java NIO-এর একটি অত্যন্ত গুরুত্বপূর্ণ উপাদান, যা একাধিক I/O চ্যানেল পরিচালনা করতে সহায়ক। এটি non-blocking I/O অ্যাপ্লিকেশনের পারফরম্যান্স উন্নত করে এবং একাধিক চ্যানেল থেকে রেডি অপারেশনগুলি পরিচালনা করতে সক্ষম করে। Selector ব্যবহার করে, আপনি একটি থ্রেডের মাধ্যমে একাধিক চ্যানেল পরিচালনা করতে পারেন, যা অ্যাপ্লিকেশনকে আরও স্কেলেবল ও কার্যকরী করে তোলে।
Selector-এর মাধ্যমে একাধিক ক্লায়েন্টের সাথে যোগাযোগ করা এবং তাদের I/O অপারেশন পরিচালনা করা খুবই সহজ এবং দ্রুত হয়, যা দক্ষ ও শক্তিশালী নেটওয়ার্ক অ্যাপ্লিকেশন তৈরি করতে সাহায্য করে।
Read more