Caja pequeña de entrada NIO (para lograr una comunicación de datos simple entre el servidor y el cliente)

              El modelo NIO (JDK1.4) es un IO sin bloqueo síncrono, que tiene tres partes principales: canal, búfer y selector. La IO tradicional funciona en función de la secuencia de bytes y la secuencia de caracteres, mientras que NIO opera en el canal y el búfer (búfer) .Los datos siempre se leen del canal al búfer o se escriben del búfer al canal. El selector (multiplexor) se utiliza para monitorear eventos de múltiples canales (por ejemplo: conexión abierta, llegada de datos). Por lo tanto, un solo hilo puede monitorear múltiples canales de datos.
              La primera gran diferencia entre NIO y IO tradicional (en lo sucesivo, IO) es que IO está orientado al flujo, mientras que NIO está orientado al búfer. Orientado a flujo de Java IO significa que cada vez que se leen uno o más bytes del flujo, hasta que se leen todos los bytes, no se almacenan en caché en ningún lugar. Además, no puede mover datos en la secuencia de un lado a otro. Si necesita mover los datos leídos de la secuencia de un lado a otro, primero debe almacenarlos en un búfer.
              Los distintos flujos de E / S están bloqueados. Esto significa que cuando un hilo llama a read () o write (), el hilo se bloquea hasta que se lean algunos datos o se escriban por completo. El hilo ya no puede hacer nada durante este período. El modo sin bloqueo de NIO permite que un hilo envíe una solicitud para leer datos de un canal, pero solo puede obtener los datos disponibles actualmente. Si actualmente no hay datos disponibles, no obtendrá nada. En lugar de mantener el hilo bloqueado, el hilo puede continuar haciendo otras cosas hasta que los datos se vuelvan legibles. Lo mismo ocurre con las escrituras sin bloqueo. Un hilo solicita escribir algunos datos en un determinado canal, pero no necesita esperar a que se escriba por completo, este hilo puede hacer otras cosas al mismo tiempo. Los subprocesos suelen utilizar el tiempo de inactividad de IO sin bloqueo para realizar operaciones de IO en otros canales, por lo que un solo subproceso ahora puede administrar varios canales de entrada y salida (canales).

Ventajas de NIO:

  1. Una especie de comunicación entre el cliente y el servidor se realiza a través del estado registrado por el Canal al Selector.
  2. Los datos en el canal se leen a través de Buffer, una forma de lectura sin bloqueo.
  3. Selector multiplexor modelo de un solo subproceso, la sobrecarga de recursos del subproceso es relativamente pequeña.

 

Código del servidor: NIOServer.java 

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
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 NIOServer {
    public static void main(String[] args) throws Exception{
        //创建一个serverSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //创建Selector
        Selector selector = Selector.open();

        //绑定端口6666,在服务端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));

        //设置非阻塞模式
        serverSocketChannel.configureBlocking(false);

        //将channel注册到selector中,关心事件为op_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //循环监听客户端连接
        while (true){
            //selector等待1s钟,如果没有事件发生则可以去做别的事情
            if(selector.select(1000)==0){
                System.out.println("服务端等待了1s,没有事件发生");
                continue;
            }

            //如果>0,则得到selectionKeys集合,已经获取到关注的事件了,selectionKeys是关注事件的集合
            //通过selectionKeys反向获取通道
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            //遍历selectionKeys集合,使用迭代器
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            while (iterator.hasNext()){
                SelectionKey key = iterator.next();

                //根据key对应的通道发生的事件做相应的处理
                //相当于有客户端连接,给该客户端生成一个socketchannel
                if(key.isAcceptable()){
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //设置为非阻塞
                    socketChannel.configureBlocking(false);
                    System.out.println("客户端连接成功,生成了一个socketchannel"+socketChannel.hashCode());
                    //将sockerchannel注册到selector,关注事件为read,同行关联一个buffer
                    socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                if(key.isReadable()){
                    //通过key反向获取socketChannel
                    SocketChannel channel = (SocketChannel)key.channel();
                    //获取到该channel关联的buffer
                    ByteBuffer buffer=(ByteBuffer)key.attachment();
                    channel.read(buffer);
                    System.out.println("客户端"+new String(buffer.array()));
                }
                //手动从集合中移除当前的selectionkey,防止重复操作
                iterator.remove();
            }
        }
    }
}

 

Código de dos clientes

NIOClient.java

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOClient {
    public static void main(String[] args) throws Exception{
        //得到一个网络通道
        SocketChannel socketChannel = SocketChannel.open();
        //设置非阻塞
        socketChannel.configureBlocking(false);
        //提供服务器端的IP和端口
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 6666);
        //连接服务器
        if(!socketChannel.connect(inetSocketAddress)){
            while (!socketChannel.finishConnect()){
                System.out.println("因为连接需要时间,客户端没有阻塞,可以做其他工作。。");
            }
        }

        //如果连接成功,发送数据
        String str="客户端ZTY已连接";
        //直接将字符串对应的字节数组包裹到buffer中,不用指定大小
        ByteBuffer buffer = ByteBuffer.wrap(str.getBytes());
        //发送数据,将buffer写入到channel
        socketChannel.write(buffer);
        System.in.read();
    }
}

NIOClient2.java

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOClient2 {
    public static void main(String[] args) throws Exception{
        //得到一个网络通道
        SocketChannel socketChannel = SocketChannel.open();
        //设置非阻塞
        socketChannel.configureBlocking(false);
        //提供服务器端的IP和端口
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 6666);
        //连接服务器
        if(!socketChannel.connect(inetSocketAddress)){
            while (!socketChannel.finishConnect()){
                System.out.println("因为连接需要时间,客户端没有阻塞,可以做其他工作。。");
            }
        }

        //如果连接成功,发送数据
        String str="客户端LPJ已连接";
        //直接将字符串对应的字节数组包裹到buffer中,不用指定大小
        ByteBuffer buffer = ByteBuffer.wrap(str.getBytes());
        //发送数据,将buffer写入到channel
        socketChannel.write(buffer);
        System.in.read();
    }
}

Ejecute el servidor primero. Captura de pantalla a continuación:

Después de ejecutar el cliente 1 (NIOClient.java), la interfaz del servidor produce un resultado:

 Después de ejecutar el cliente 2 (NIOClient2.java), la interfaz del servidor produce un resultado:

 

Después de terminar NIO, no está lejos de dominar a Netty, porque Netty se basa en NIO. 

Supongo que te gusta

Origin blog.csdn.net/Zhongtongyi/article/details/107348605
Recomendado
Clasificación