Rumah >Java >javaTutorial >Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)

Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)

WBOY
WBOYke hadapan
2022-03-31 11:54:051824semak imbas

Artikel ini membawa anda pengetahuan yang berkaitan tentang java, yang terutamanya memperkenalkan isu berkaitan NIO, termasuk teras NIO, perbandingan antara BIO dan NIO, dan pelaksanaan pelanggan pelayan mudah melalui komunikasi Terminal NIO, saya harap ia akan membantu semua orang.

Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)

Disyorkan kajian: "tutorial java"

1. Peta minda Java

Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)

2. Model I/O

Intipati model I/O ialah saluran yang digunakan untuk menghantar dan menerima data, yang sebahagian besarnya menentukan prestasi komunikasi program.
Java menyokong tiga model pengaturcaraan rangkaian: BIO, NIO, AIO

  • BIO: penyegerakan dan penyekatan, mod pelaksanaan perkhidmatan ialah satu sambungan dan satu utas, iaitu, pelanggan mempunyai satu sambungan Apabila membuat permintaan, pelayan perlu memulakan benang untuk pemprosesan.

  • NIO: Segerak dan tidak menyekat, mod pelaksanaan pelayan ialah benang memproses sambungan permintaan berbilang, iaitu permintaan yang dihantar oleh pelanggan akan didaftarkan kepada pemultipleks dan dimultiplekskan Pelayan meninjau sambungan dan memprosesnya jika terdapat permintaan I/O.

  • AIO: Asynchronous non-blocking, AIO memperkenalkan konsep saluran tak segerak, menggunakan mod Proactor, memudahkan penulisan program dan hanya memulakan urutan selepas permintaan yang sah terlebih dahulu Beritahu pelayan selepas selesai.

3. Senario aplikasi BIO, NIO, AIO

  • Kaedah BIO sesuai untuk seni bina dengan bilangan sambungan yang agak kecil dan tetap. Kaedah ini sesuai untuk Keperluan sumber pelayan agak tinggi, dan concurrency terhad kepada aplikasi Ia adalah satu-satunya pilihan sebelum JDK1.4, tetapi program ini mudah dan mudah difahami.

  • Kaedah NIO sesuai untuk seni bina dengan bilangan sambungan yang banyak dan sambungan yang agak pendek (operasi ringan), seperti pelayan sembang, sistem barraj, komunikasi antara pelayan, dsb. Pengaturcaraan adalah lebih rumit, dan JDK1.4 mula menyokongnya.

  • Kaedah AIO digunakan dalam seni bina dengan bilangan sambungan yang besar dan sambungan yang agak panjang (operasi berat), seperti pelayan album foto memanggil OS sepenuhnya untuk mengambil bahagian dalam operasi serentak . Pengaturcaraan agak rumit, dan JDK7 mula menyokongnya

4 Proses pengaturcaraan BIO yang mudah

  • Pelayan memulakan ServerSocket

  • Pelanggan memulakan Soket Untuk berkomunikasi dengan pelayan, secara lalai pelayan perlu mewujudkan urutan untuk setiap pelanggan untuk berkomunikasi dengannya; >Selepas pelanggan menghantar permintaan, ia terlebih dahulu merujuk pelayan sama ada terdapat tindak balas thread, jika tidak Ia akan menunggu atau ditolak; akan menunggu permintaan untuk tamat sebelum meneruskan pelaksanaan;

  • 5 , teras NIO

  • NIO mempunyai tiga bahagian teras: Pemilih (pemilih), Saluran (saluran) dan Penampan (buffer).
  • NIO berorientasikan penimbal, atau pengaturcaraan berorientasikan blok Data dibaca ke dalam penimbal yang diproses kemudiannya Ia menyediakan rangkaian yang tidak menyekat dan berskala tinggi.

    HTTP2.0 menggunakan teknologi pemultipleksan untuk membenarkan sambungan yang sama memproses berbilang permintaan secara serentak, dan bilangan permintaan serentak adalah beberapa susunan magnitud yang lebih besar daripada HTTP1.1.

    Ringkasnya, NIO boleh mengendalikan berbilang permintaan dengan satu urutan.
6. Perbandingan antara BIO dan NIO


BIO memproses data dalam aliran, manakala NIO memproses data dalam blok I/O lebih cekap daripada aliran I /O adalah jauh lebih tinggi; dan NIO beroperasi berdasarkan Saluran dan Data sentiasa dibaca dari saluran ke penimbal, atau ditulis dari penimbal ke saluran. Pemilih digunakan untuk memantau berbilang acara saluran (seperti permintaan sambungan, ketibaan data, dll.), jadi satu rangkaian boleh memantau berbilang saluran pelanggan.

7. Gambarajah skematik tiga prinsip teras NIO

  • Penerangan carta alir:

  • Pemilih yang sepadan Satu utas, satu utas sepadan dengan berbilang saluran (sambungan);

  • Setiap saluran akan sepadan dengan Penampan;
  • Saluran yang mana program beralih ditentukan oleh acara dan Acara ialah konsep penting;

Pemilih akan menghidupkan setiap saluran mengikut acara yang berbeza;

Data dibaca dan ditulis melalui Buffer, yang sama dengan BIO ialah sama ada aliran input atau aliran keluaran, yang tidak boleh dwiarah, tetapi Penampan NIO boleh dibaca atau ditulis dan memerlukan flip. kaedah untuk menukar Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)

  • saluran adalah dwiarah dan boleh mengembalikan status sistem pengendalian asas Sebagai contoh, Linux, saluran sistem pengendalian asas adalah dua hala; Penampan (buffer)

  • Penimbal pada asasnya ialah blok memori yang boleh membaca dan menulis data Ia boleh difahami sebagai objek bekas (termasuk tatasusunan). lebih mudah, Objek penimbal mempunyai beberapa mekanisme terbina dalam yang boleh menjejaki dan merekodkan perubahan status penimbal. Saluran menyediakan saluran untuk membaca data daripada fail dan rangkaian, tetapi data yang dibaca atau ditulis mesti melalui Penampan. Dalam NIO, Buffer ialah kelas induk peringkat atas, iaitu kelas abstrak.

    1. Senarai subkelas Penimbal yang biasa digunakan

    ByteBuffer, menyimpan data bait ke dalam penimbal;

    ShortBuffer, menyimpan data rentetan ke dalam penimbal;
    • CharBuffer, menyimpan data aksara ke dalam penimbal; ke penimbal;
    • LongBuffer, menyimpan data integer panjang ke dalam penimbal; 🎜>
    • FloatBuffer, menyimpan perpuluhan dalam penimbal; 🎜>tanda: tanda

    • kedudukan: kedudukan, indeks elemen seterusnya untuk dibaca atau ditulis, nilai akan ditukar setiap kali data penimbal dibaca atau ditulis, seperti berikut Persediaan membaca dan menulis.

    • had: Menunjukkan titik akhir semasa penimbal tidak boleh dilakukan pada lokasi penimbal melebihi had. Dan had boleh diubah suai

    • kapasiti: kapasiti, iaitu jumlah maksimum data yang boleh ditampung ia ditetapkan apabila penimbal dibuat dan tidak boleh diubah.

    3. Api penimbal biasa

    Api yang diperkenalkan dalam JDK1.4

    • kapasiti int akhir awam( )//Mengembalikan kapasiti penimbal ini

      kedudukan int akhir awam( )//Mengembalikan kedudukan penimbal ini
    • kedudukan Penampan akhir awam ( int newPositio)//Tetapkan kedudukan penimbal ini

      had int akhir awam()//Kembalikan had penimbal ini
    • had Penampan akhir awam (int newLimit)//Tetapkan Kawasan penimbal ini sekatan

      tanda Penampan akhir awam()//Tetapkan tanda pada kedudukan penimbal ini
    • set semula Penampan akhir awam()//Tetapkan semula kedudukan penimbal ini kepada tanda sebelumnya Kedudukan daripada

      Penimbal akhir awam clear( )//Kosongkan penimbal ini, iaitu, pulihkan setiap tanda kepada keadaan asalnya, tetapi data sebenarnya tidak dipadamkan dan operasi seterusnya akan menimpa
    awam penampan akhir flip( )//Terbalikkan penimbal ini

    Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)pulangan penimbal akhir awam( )//Pulihkan penimbal ini

    int akhir awam baki()//Kembali antara kedudukan semasa dan had bilangan elemenboolean akhir awam hasRemaining()//Memaklumkan sama ada terdapat elemen antara kedudukan semasa dan had

    boolean abstrak awam isReadOnly();//Memaklumkan sama ada penimbal ini hanya Baca penimbal

    • api yang diperkenalkan dalam JDK1.6
    • boolean abstrak awam hasArray();//Maklumkan sama ada penimbal ini mempunyai tatasusunan pelaksanaan asas yang boleh diakses
    • public abstract Object array();//Mengembalikan tatasusunan pelaksanaan asas penimbal ini
    • public abstract int arrayOffset();//Mengembalikan penimbal pertama dalam tatasusunan pelaksanaan asas penimbal ini Mengimbangi elemen kawasan
    • boolean abstrak awam isDirect();//Maklumkan sama ada penimbal ini ialah penimbal langsung
    • Saluran
    • 1. Pengenalan asas
    • (1) Saluran NIO serupa dengan strim
    • Saluran boleh dibaca dan ditulis pada masa yang sama , manakala strim hanya boleh membaca atau tulis;
    Saluran boleh membaca dan menulis data secara tak segerak

    Saluran boleh membaca data daripada penimbal dan menulis data ke penimbal
    • (2) Strim dalam BIO ialah satu -cara. Contohnya, objek FileInputStream hanya boleh membaca data, manakala saluran (Saluran) dalam NIO adalah dua arah dan boleh membaca dan menulis operasi.
    • (3) Saluran ialah antara muka dalam NIO
    • (4) Kelas Saluran yang biasa digunakan termasuk: FileChannel, DatagramChannel, ServerSocketChannel dan SocketChannel. ServerSocketChanne serupa dengan ServerSocket, dan SocketChannel serupa dengan Socket.
    • (5) FileChannel digunakan untuk membaca dan menulis data fail, DatagramChannel digunakan untuk membaca dan menulis data UDP, ServerSocketChannel dan SocketChannel digunakan untuk membaca dan menulis data TCP.
    • 2. FileChannel

    Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)FileChannel digunakan terutamanya untuk melaksanakan operasi IO pada fail tempatan ialah:

    baca , baca data daripada saluran dan masukkannya ke dalam penimbal

    tulis, tulis data dalam penimbal ke dalam saluran

    • pindahDari, dari Salin data dari saluran sasaran ke saluran semasa
    • transferTo, salin data dari saluran semasa ke saluran sasaran

    3. Nota dan butiran tentang Penampan dan Saluran

    • ByteBuffer menyokong taip put dan get, put put Apakah jenis data itu , get harus menggunakan jenis data yang sepadan untuk mendapatkannya, jika tidak, mungkin terdapat pengecualian BufferUnderflowException.

    • Boleh menukar Penampan biasa menjadi Penampan baca sahaja.

    • NIO juga menyediakan MappedByteBuffer, yang membenarkan fail diubah suai terus dalam ingatan (memori di luar timbunan), dan cara menyegerakkan ke fail diselesaikan oleh NIO.

    • NIO juga menyokong operasi membaca dan menulis melalui berbilang Penampan (iaitu tatasusunan Penampan), iaitu Penyebaran dan Pengumpulan.

    10. Pemilih (pemilih)

    1 Pengenalan asas

    • Java’s NIO , menggunakan. mod IO tidak menyekat. Anda boleh menggunakan satu utas untuk mengendalikan berbilang sambungan pelanggan, dan anda akan menggunakan Pemilih.

    • Pemilih boleh mengesan sama ada sesuatu peristiwa berlaku pada berbilang saluran berdaftar Jika sesuatu peristiwa berlaku, ia akan memperoleh acara itu dan memproses setiap acara dengan sewajarnya. Dengan cara ini, hanya satu urutan boleh digunakan untuk mengurus berbilang saluran, iaitu, untuk mengurus berbilang sambungan dan permintaan.

    • Membaca dan menulis hanya akan berlaku apabila terdapat acara baca dan tulis sebenar pada sambungan/saluran, yang mengurangkan overhed sistem dan menghapuskan keperluan untuk mencipta urutan untuk setiap sambungan No perlu mengekalkan beberapa benang.

    • Mengelakkan overhed yang disebabkan oleh penukaran konteks antara berbilang urutan.

    2 kaedah berkaitan pemilih

    • buka();//Dapatkan objek pemilih

    • pilih(masa tamat lama);//Pantau semua saluran yang didaftarkan apabila operasi IO boleh dilakukan, tambahkan SelectionKey yang sepadan pada koleksi dalaman dan kembalikan parameter tersebut untuk menetapkan masa tamat >

    • selectedKeys();//Dapatkan semua SelectionKeys daripada koleksi dalaman.

    3. Nota

    Fungsi ServerSocketChannel dalam NIO adalah serupa dengan ServerSocket, dan fungsi SocketChannel adalah serupa dengan Socket.

    11. Komunikasi pelayan-klien yang ringkas melalui NIO

    1 Pelayan

    package com.nezha.guor.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.*;import java.util.Iterator;public class NioServer {
        private Selector selector;
        private ServerSocketChannel serverSocketChannel;
        private static final int PORT = 8080;
    
        public NioServer() {
            try {
                //获得选择器
                selector = Selector.open();
                serverSocketChannel =  ServerSocketChannel.open();
                //绑定端口
                serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
                //设置非阻塞模式
                serverSocketChannel.configureBlocking(false);
                //将该ServerSocketChannel 注册到selector
                serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            }catch (IOException e) {
                System.out.println("NioServer error:"+e.getMessage());
            }
        }
    
        public void listen() {
    
            System.out.println("监听线程启动: " + Thread.currentThread().getName());
            try {
                while (true) {
                    int count = selector.select();
                    if(count > 0) {
                        //遍历得到selectionKey集合
                        Iterator<selectionkey> iterator = selector.selectedKeys().iterator();
                        while (iterator.hasNext()) {
                            SelectionKey key = iterator.next();
    
                            if(key.isAcceptable()) {
                                SocketChannel sc = serverSocketChannel.accept();
                                sc.configureBlocking(false);
                                sc.register(selector, SelectionKey.OP_READ);
                                System.out.println(sc.getRemoteAddress() + " 上线 ");
                            }
                            //通道发送read事件,即通道是可读的状态
                            if(key.isReadable()) {
                                getDataFromChannel(key);
                            }
                            //当前的key 删除,防止重复处理
                            iterator.remove();
                        }
                    } else {
                        System.out.println("等待中");
                    }
                }
            }catch (Exception e) {
                System.out.println("listen error:"+e.getMessage());
            }
        }
    
        private void getDataFromChannel(SelectionKey key) {
            SocketChannel channel = null;
            try {
                channel = (SocketChannel) key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(1024);
    
                int count = channel.read(buffer);
                //根据count的值做处理
                if(count > 0) {
                    String msg = new String(buffer.array());
                    System.out.println("来自客户端: " + msg);
    
                    //向其它的客户端转发消息(排除自己)
                    sendInfoToOtherClients(msg, channel);
                }
            }catch (IOException e) {
                try {
                    System.out.println(channel.getRemoteAddress() + " 离线了");
                    //取消注册
                    key.cancel();
                }catch (IOException ex) {
                    System.out.println("getDataFromChannel error:"+ex.getMessage());
                }
            }finally {
                try {
                    channel.close();
                }catch (IOException ex) {
                    System.out.println("channel.close() error:"+ex.getMessage());
                }
            }
        }
    
        //转发消息给其它客户(通道)
        private void sendInfoToOtherClients(String msg, SocketChannel self ) throws  IOException{
            System.out.println("服务器转发消息中...");
            System.out.println("服务器转发数据给客户端线程: " + Thread.currentThread().getName());
            //遍历 所有注册到selector 上的 SocketChannel,并排除 self
            for(SelectionKey key: selector.keys()) {
                Channel targetChannel = key.channel();
    
                //排除自己
                if(targetChannel instanceof  SocketChannel && targetChannel != self) {
                    SocketChannel dest = (SocketChannel)targetChannel;
                    //将信息存储到buffer
                    ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                    //将buffer数据写入通道
                    dest.write(buffer);
                }
            }
        }
    
        public static void main(String[] args) {
            //创建服务器对象
            NioServer nioServer = new NioServer();
            nioServer.listen();
        }}</selectionkey>

    2 🎜>

    3. Output konsol
    package com.nezha.guor.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Scanner;public class NioClient {
        private final int PORT = 8080; //服务器端口
        private Selector selector;
        private SocketChannel socketChannel;
        private String username;
    
        public NioClient() throws IOException {
            selector = Selector.open();
            socketChannel = socketChannel.open(new InetSocketAddress("127.0.0.1", PORT));
            //设置非阻塞
            socketChannel.configureBlocking(false);
            //将channel注册到selector
            socketChannel.register(selector, SelectionKey.OP_READ);
            username = socketChannel.getLocalAddress().toString().substring(1);
            System.out.println(username + " is ok...");
        }
    
        //向服务器发送消息
        public void sendInfo(String info) {
            info = username + " 说:" + info;
            try {
                socketChannel.write(ByteBuffer.wrap(info.getBytes()));
            }catch (IOException e) {
                System.out.println("sendInfo error:"+e.getMessage());
            }
        }
    
        //读取从服务器端回复的消息
        public void readInfo() {
            try {
                int readChannels = selector.select();
                if(readChannels > 0) {
                    Iterator<selectionkey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        if(key.isReadable()) {
                            //得到相关的通道
                            SocketChannel sc = (SocketChannel) key.channel();
                            //得到一个Buffer
                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                            //读取
                            sc.read(buffer);
                            //把读到的缓冲区的数据转成字符串
                            String msg = new String(buffer.array());
                            System.out.println(msg.trim());
                        }
                    }
                    iterator.remove(); //删除当前的selectionKey, 防止重复操作
                } else {
                    System.out.println("没有可以用的通道...");
                }
            }catch (Exception e) {
                System.out.println("readInfo error:"+e.getMessage());
            }
        }
    
        public static void main(String[] args) throws Exception {
            NioClient nioClient = new NioClient();
            new Thread() {
                public void run() {
                    while (true) {
                        nioClient.readInfo();
                        try {
                            Thread.currentThread().sleep(2000);
                        }catch (InterruptedException e) {
                            System.out.println("sleep error:"+e.getMessage());
                        }
                    }
                }
            }.start();
    
            //发送数据给服务器端
            Scanner scanner = new Scanner(System.in);
    
            while (scanner.hasNextLine()) {
                nioClient.sendInfo(scanner.nextLine());
            }
        }}</selectionkey>

    Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)
    Pembelajaran yang disyorkan: "Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan)tutorial java

    Atas ialah kandungan terperinci Membawa anda untuk menguasai sepenuhnya Java NIO (perkongsian ringkasan). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

    Kenyataan:
    Artikel ini dikembalikan pada:csdn.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam