Caixa pequena de entrada NIO (para conseguir comunicação de dados simples entre o servidor e o cliente)

              O modelo NIO (JDK1.4) é um IO sem bloqueio síncrono, que tem três partes principais: Canal, Buffer e Seletor. O IO tradicional opera com base no fluxo de bytes e no fluxo de caracteres, enquanto o NIO opera no canal e no buffer (buffer) .Os dados são sempre lidos do canal para o buffer ou gravados do buffer para o canal. Seletor (multiplexador) é usado para monitorar eventos de vários canais (por exemplo: conexão aberta, chegada de dados). Portanto, um único thread pode monitorar vários canais de dados.
              A primeira grande diferença entre NIO e IO tradicional (doravante referido como IO) é que IO é orientado por fluxo, enquanto NIO é orientado por buffer. Orientado a fluxo Java IO significa que cada vez que um ou mais bytes são lidos do fluxo, até que todos os bytes sejam lidos, eles não são armazenados em cache em nenhum lugar. Além disso, ele não pode mover dados no fluxo para frente e para trás. Se você precisar mover os dados lidos do fluxo para frente e para trás, primeiro será necessário armazená-los em um buffer.
              Os vários fluxos de IO estão bloqueados. Isso significa que quando um thread chama read () ou write (), o thread é bloqueado até que alguns dados sejam lidos ou os dados sejam completamente gravados. O tópico não pode mais fazer nada durante este período. O modo sem bloqueio do NIO permite que um thread envie uma solicitação para ler dados de um canal, mas ele só pode obter os dados disponíveis no momento. Se não houver dados disponíveis no momento, ele não obterá nada. Em vez de manter o thread bloqueado, ele pode continuar a fazer outras coisas até que os dados se tornem legíveis. O mesmo é verdadeiro para gravações sem bloqueio. Um thread solicita a gravação de alguns dados em um determinado canal, mas não precisa esperar que sejam completamente gravados, este thread pode fazer outras coisas ao mesmo tempo. Threads geralmente usam o tempo ocioso de IO sem bloqueio para realizar operações de IO em outros canais, portanto, um único thread agora pode gerenciar vários canais de entrada e saída (canais).

Vantagens NIO:

  1. Uma espécie de comunicação entre o cliente e o servidor é realizada através do estado cadastrado pelo Canal ao Seletor.
  2. Os dados no Canal são lidos através do Buffer, uma forma de leitura sem bloqueio.
  3. Modelo de encadeamento único multiplexador de seletor, sobrecarga de recurso de encadeamento é relativamente pequeno.

 

Código do 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();
            }
        }
    }
}

 

Dois códigos de cliente

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();
    }
}

Execute o servidor primeiro. Captura de tela abaixo:

Depois de executar o cliente 1 (NIOClient.java), a interface do servidor produz a saída:

 Depois de executar o cliente 2 (NIOClient2.java), a interface do servidor produz a saída:

 

Depois de terminar o NIO, não está longe de dominar o Netty, porque o Netty é baseado no NIO. 

Acho que você gosta

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