Cet article vous apporte des connaissances pertinentes sur java, qui présente principalement les problèmes liés à NIO, y compris le noyau NIO, la comparaison entre BIO et NIO et la simple communication serveur-client via NIO. J'espère que cela sera utile à tout le monde.
Étude recommandée : "Tutoriel Java"
HTTP2.0 utilise la technologie de multiplexage pour permettre à la même connexion de traiter plusieurs requêtes simultanément, et le nombre de requêtes simultanées est plusieurs ordres de grandeur supérieur à celui de HTTP1.1.
En bref, NIO peut gérer plusieurs requêtes avec un seul thread.
6. Comparaison entre BIO et NIO
Description de l'organigramme :
le canal est bidirectionnel et peut renvoyer l'état du système d'exploitation sous-jacent. Par exemple, Linux, le canal du système d'exploitation sous-jacent est bidirectionnel
Un tampon est essentiellement un tampon qui peut être lu et lu. écrit Le bloc mémoire de données peut être compris comme un objet conteneur (y compris un tableau). Cet objet fournit un ensemble de méthodes pour faciliter l'utilisation du bloc mémoire. L'objet tampon possède des mécanismes intégrés qui peuvent suivre et enregistrer. l'état du tampon changeant de circonstances. Channel fournit un canal pour lire les données des fichiers et des réseaux, mais les données lues ou écrites doivent passer par Buffer.
Dans NIO, Buffer est une classe parent de niveau supérieur, qui est une classe abstraite.
ByteBuffer, stocke les données d'octets dans le tampon ;
ShortBuffer, stocke les données de chaîne dans le tampon
CharBuffer, stocke les données de caractères dans le tampon ; Area ;
IntBuffer, stocke les données entières dans le tampon ;
LongBuffer, stocke les données entières longues dans le tampon
DoubleBuffer, stocke les décimales dans le tampon ; des mals à le tampon ;
position : position, l'index du prochain élément à lire ou à écrire, à chaque fois que les données du tampon sont lu ou écrit La valeur sera modifiée à chaque fois pour préparer la prochaine lecture et écriture.
limite : indique le point final actuel du tampon. Les opérations de lecture et d'écriture ne peuvent pas être effectuées sur les positions où le tampon dépasse la limite. Et la limite peut être modifiée
capacité : capacité, c'est-à-dire la quantité maximale de données pouvant être hébergées ; elle est définie lors de la création du tampon et ne peut pas être modifiée ;
3. L'API introduite lorsque le tampon est couramment utilisé api
Les canaux peuvent lire des données à partir de tampons et vous pouvez écrire des données dans le tampon
FileChannel est principalement utilisé pour effectuer des opérations d'E/S sur des fichiers locaux. Les méthodes courantes sont :
ByteBuffer prend en charge les types put et get. Quel que soit le type de données saisi, get doit utiliser le type de données correspondant pour le récupérer, sinon il peut y avoir une exception BufferUnderflowException. .
Vous pouvez convertir un Buffer normal en un Buffer en lecture seule.
NIO fournit également MappedByteBuffer, qui permet de modifier les fichiers directement en mémoire (mémoire en dehors du tas), et la synchronisation avec les fichiers est complétée par NIO.
NIO prend également en charge les opérations de lecture et d'écriture via plusieurs tampons (c'est-à-dire des tableaux de tampons), à savoir la diffusion et le rassemblement.
NIO de Java, utilisant la méthode IO non bloquante. Vous pouvez utiliser un seul thread pour gérer plusieurs connexions client et vous utiliserez le sélecteur.
Selector peut détecter si un événement se produit sur plusieurs canaux enregistrés. Si un événement se produit, l'événement est obtenu et chaque événement est traité en conséquence. De cette manière, un seul thread peut être utilisé pour gérer plusieurs canaux, c'est-à-dire pour gérer plusieurs connexions et requêtes.
Seulement lorsque la connexion/le canal a réellement un événement de lecture ou d'écriture, la lecture et l'écriture seront effectuées, ce qui réduit considérablement la surcharge du système, et il n'est pas nécessaire de créer un thread pour chaque connexion et de maintenir plusieurs threads.
Évitez la surcharge causée par le changement de contexte entre plusieurs threads.
open();//Obtenir un objet sélecteur
select(long timeout);//Surveiller tous les canaux enregistrés lorsqu'ils contiennent des opérations d'E/S Lorsque cela est possible , ajoutez la SelectionKey correspondante à la collection interne et renvoyez-la. Les paramètres sont utilisés pour définir le délai d'attente
selectedKeys( //Obtenir toutes les SelectionKeys de la collection interne.
La fonction ServerSocketChannel dans NIO est similaire à ServerSocket et la fonction SocketChannel est similaire à Socket.
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>
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>
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!