1. Pengantar Perpustakaan Nio
1. Buffer buffer
Buffer adalah objek yang berisi beberapa data yang akan ditulis dan dibacakan.
Di NIO, semua data diproses dalam buffer. Saat membaca data, itu dibaca langsung dari saluran ke buffer, dan ketika menulis data, itu juga ditulis dari buffer ke saluran.
Buffer pada dasarnya adalah array, biasanya array byte (bytebuffer), atau jenis array lainnya. Selain itu, buffer juga menyediakan informasi seperti akses terstruktur ke data dan memelihara lokasi baca dan tulis.
Hubungan warisan kelas buffer ditunjukkan pada gambar di bawah ini:
2. Saluran
Saluran adalah saluran di mana data jaringan dibaca dan ditulis melalui saluran. Perbedaan antara saluran dan aliran adalah bahwa saluran tersebut adalah dua arah (saluran dapat digunakan untuk membaca dan menulis yang terakhir pada saat yang sama), dan aliran hanya bergerak dalam satu arah.
Saluran dapat dibagi secara kasar menjadi dua kategori: SelectableChannel untuk membaca dan menulis jaringan (ServerSocketchannel dan Socketchannel adalah subclass mereka), dan FileChannel untuk operasi file.
Contoh berikut menunjukkan file menggunakan FileChannel untuk menulis data ke file, membaca data dari file, dan menyalin data file ke file lain:
kelas publik niotest {public static void main (string [] args) melempar ioException {copyFile (); } // Salin file private static void copyFile () {fileInputStream in = null; FileOutputStream out = null; coba {in = new fileInputStream ("src/main/java/data/in---aben.txt"); out = FileOutputStream baru ("src/main/java/data/out-data.txt"); Filechannel inchannel = in.getchannel (); Filechannel outchannel = out.getchannel (); Bytebuffer buffer = bytebuffer.allocate (1024); int bytesread = inchannel.read (buffer); while (bytesread! =-1) {buffer.flip (); outchannel.write (buffer); buffer.clear (); bytesread = inchannel.read (buffer); }} catch (FileNotFoundException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); } catch (ioException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); }} // Tulis file private static void writeFilenio () {coba {randomAccessFile fout = randomAccessFile baru ("src/main/java/data/nio-data.txt", "rw"); Filechannel fc = fout.getchannel (); Bytebuffer buffer = bytebuffer.allocate (1024); buffer.put ("hi123" .getbytes ()); buffer.flip (); coba {fc.write (buffer); } catch (ioException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); }} catch (FileNotFoundException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); }} // Baca file private static void readFilenio () {fileInputStream FileInputStream; coba {fileInputStream = FileInputStream baru ("src/main/java/data/nio-data.txt"); FileChannel fileChannel=fileInputStream.getChannel();//Get channel from FileInputStream ByteBuffer byteBuffer=ByteBuffer.allocate(1024);//Create a buffer int bytesRead=fileChannel.read(byteBuffer);//Read the data to the buffer while(bytesRead!=-1) { /*limit=position * position=0; */ byteBuffer.flip (); // hasRemaining (): menginformasikan apakah ada elemen antara posisi saat ini dan batas while (byteBuffer.hasremaining ()) {System.out.print ((char) bytebuffer.get ()); } /** Hapus Posisi* Posisi = 0; * batas = kapasitas; */ byteBuffer.clear (); bytesread = filechannel.read (bytebuffer); }} catch (FileNotFoundException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); } catch (ioException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); }}}3. Pemilih Multiplexer
Multiplexer menyediakan kemampuan untuk memilih tugas yang siap. Pemilih akan terus -menerus polling saluran yang terdaftar di atasnya. Jika saluran mengirim acara baca atau tulis, saluran akan berada dalam keadaan siap dan akan disurvei oleh pemilih. Kemudian, himpunan saluran siap dapat diperoleh melalui seleksi untuk melakukan operasi I/O berikutnya.
Pemilih multiplexer dapat melakukan polling beberapa saluran secara bersamaan. Karena JDK menggunakan Epoll alih -alih implementasi terpilih tradisional, ia tidak memiliki batas pegangan koneksi maksimum 1024/2048, yang berarti bahwa hanya satu utas yang harus bertanggung jawab atas jajak pendapat pemilih dan dapat mengakses ribuan klien. Model ini ditunjukkan pada gambar di bawah ini:
Proses pemilih dengan satu utas. Untuk menggunakan pemilih, Anda harus mendaftarkan saluran dengan pemilih dan kemudian memanggil metode pilih (). Metode ini akan diblokir hingga saluran terdaftar sudah siap. Setelah metode ini kembali, utas dapat memproses peristiwa ini, seperti koneksi baru, penerimaan data, dll.
Catatan:
1. Model pilihan apa?
Select adalah mekanisme pemicu peristiwa, yang memicu pemrosesan ketika peristiwa tunggu terjadi, dan sebagian besar digunakan untuk pemrosesan klien dengan implementasi Linux dari server.
Ini secara bersamaan dapat mendeteksi satu set perangkat IO yang tidak memblokir yang mendukung non-blocking, apakah ada peristiwa (seperti output kesalahan prioritas yang dapat dibaca, dapat dibaca, dan prioritas tinggi, dll.) Sampai perangkat memicu peristiwa atau melebihi waktu tunggu yang ditentukan. Artinya, tanggung jawab mereka bukan untuk melakukan IO, tetapi untuk membantu penelepon menemukan perangkat yang saat ini siap.
2. Apa model Epoll?
Gagasan desain Epoll adalah untuk membagi operasi tunggal Select/Poll menjadi 1 Epoll_Create + Multiple Epoll_Ctrl + satu tunggu. Selain itu, kernel telah menambahkan sistem file "EventPollfs" untuk operasi Epoll. Setiap atau lebih deskriptor file yang akan dipantau memiliki simpul inode dari sistem file EventPollFS yang sesuai, dan informasi utama disimpan dalam struktur EventPoll. Informasi penting dari file yang dipantau disimpan dalam struktur Epitem. Jadi mereka adalah hubungan satu-ke-banyak.
2. Pengembangan sisi server NIO
Deskripsi Fungsi: Nyalakan sisi server dan kirim hello string ke setiap klien akses.
Ada beberapa langkah utama untuk menggunakan NIO untuk pengembangan sisi server:
1. Buat ServerSocketchannel dan konfigurasikan ke mode non-blocking
serversocketchannel = serversocketchannel.open (); serversocketchannel.configureblocking (false);
2. Bind Mendengarkan dan Konfigurasikan Parameter TCP, seperti ukuran backlog
serversocketchannel.socket (). Bind (inetsocketaddress baru (8080));
3. Buat utas I/O independen untuk polling pemilih multiplexer
4. Buat pemilih, daftarkan serversocketchannel yang Anda buat sebelumnya ke pemilih, dan dengarkan selectionKey.cepcept
selector = selector.open (); serversocketchannel.register (selector, selectionkey.op_accept);
5. Mulai utas I/O, jalankan metode selector.select () di badan loop, dan jajak pendapat saluran siap
while (true) {coba {// pilih () blok sampai setidaknya satu saluran siap pada acara yang Anda daftarkan // Jika tidak ada saluran yang siap, itu akan memblokir di sini // Pilih (waktu lama) sama dengan Select (), kecuali bahwa itu akan memblokir batas waktu milidetik (parameter). selector.select (); } catch (ioException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); merusak; }}6. Saat polling saluran di negara yang siap, itu perlu dinilai. Jika itu adalah status OP_ACCECT, itu berarti itu adalah akses klien baru. Kemudian hubungi serversocketchannel.accept () metode untuk menerima klien baru.
// kembalikan seleksi siap pakai, dan kemudian beralih untuk mengeksekusi set <dectionKey> readkeys = selector.selectedKeys (); untuk (iterator <dectionKey> it = readkeys.iterator (); it.hasnext ();) {selectionKey key = it.next (); it.remove (); coba {if (key.isacceptable ()) {serversocketchannel server = (serversocketchannel) key.channel (); Socketchannel client = server.accept (); client.configureblocking (false); client.register (selector, selectionkey.op_write); } else if (key.iswritable ()) {socketchannel client = (socketchannel) key.channel (); Bytebuffer buffer = bytebuffer.allocate (20); String str = "halo"; buffer = byteBuffer.wrap (str.getbytes ()); client.write (buffer); key.cancel (); }} catch (ioException e) {E.PrintStackTrace (); key.cancel (); coba {key.channel (). close (); } catch (IoException E1) {// TODO AUTO-ENCEALATED Catch Block E1.PrintStackTrace (); }}}7. Atur socketchannel tautan klien yang baru diakses ke mode non-blocking, dan konfigurasikan beberapa parameter TCP lainnya.
if (key.isacceptable ()) {serversocketchannel server = (serversocketchannel) key.channel (); Socketchannel client = server.accept (); client.configureblocking (false); ...}8. Daftarkan Socketchannel ke Pemilih dan Dengarkan OP_WRITE
client.register (selector, selectionkey.op_write);
9. Jika saluran yang disurvei adalah OP_WRITE, itu berarti bahwa data harus ditulis ke dalam sockchannel, maka objek BYTEBUFFER dibangun dan paket data ditulis.
lain if (key.iswritable ()) {socketchannel client = (socketchannel) key.channel (); Bytebuffer buffer = bytebuffer.allocate (20); String str = "halo"; buffer = byteBuffer.wrap (str.getbytes ()); client.write (buffer); key.cancel (); }Kode lengkapnya adalah sebagai berikut:
impor java.io.ioException; impor java.net.inetsocketaddress; impor java.nio.bytebuffer; impor java.nio.channels.selectionKey; import java.nio.channels.selector; impor java.nio.channels.selektor; impor java.nio.nio. java.nio.channels.socketchannel; import java.util.iterator; import java.util.set; server kelas publik serverchetchanneldemo {public static void main (string [] args) {serversocketchannel serversocketchannel; selector selector = null; try {serversocketchannel serversocketchannel; selector selector = null; null {serversocketchannel serversocketchan; selector selector = null; null {serversocketchannel; Serversocketchannel.open (); serversocketchannel.configureblocking (false); serversocketchannel.socket (). Bind (inetsocketAddress baru (8080)); selector = selector.open (); serversocketchannel.register (selector, selectionkey.op_accepcing); oM-comple-{{{{o) {{{o) {o); blocke.printstacktrace ();} while (true) {coba {// select () blok sampai setidaknya satu saluran siap pada acara yang Anda daftarkan // Jika tidak ada saluran yang siap, itu akan diblokir di sini sepanjang waktu.//Select(long timeout) sama dengan Select (), kecuali bahwa itu akan memblokir milliseconds (paramer Param). selector.select ();} catch (ioException e) {// tODO Auto-dibuat tangkapan blocke.printstacktrace (); break;} // kembalikan seleksi siap saji, dan kemudian beralih untuk mengeksekusi set <dection> {selections. key = it.next (); it.remove (); coba {if (key.isacceptable ()) {serversocketchannel server = (serversocketchannel) key.channel (); socketchannel client = server.accept (); client.configureBlocking (false); client.Register (selector,); client.configureBlocking (false); client.register (selector, selection); client.configureBlocking (false); client.register (selector, selection); {Socketchannel client = (socketchannel) key.channel (); byteBuffer buffer = byteBuffer.allocate (20); string str = "hello"; buffer = byteBuffer.wrap (str.getbytes ()); client.write (buffer); key.cancel ();} tangkap ()); client.write (buffer); key.cancel ();} catch (ioccepte); {E.PrintStackTrace (); key.cancel (); coba {key.channel (). Tutup ();} catch (ioException e1) {// TODO AUTO-ENTO-GOTERATED Catch Blocke1.printStackTrace ();}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}Kami menggunakan telnet localhost 8080 untuk mensimulasikan banyak klien:
Hasil menjalankan program adalah sebagai berikut:
Meringkaskan
Di atas adalah semua penjelasan terperinci dari pengembangan sisi server Java Nio dalam artikel ini, saya harap ini akan membantu semua orang. Teman yang tertarik dapat terus merujuk ke topik terkait lainnya di situs ini. Jika ada kekurangan, silakan tinggalkan pesan untuk menunjukkannya. Terima kasih teman atas dukungan Anda untuk situs ini!