【JAVA】IO

NIO核心组件:

  缓冲区Buffer:包在对象内的基本数据元素数组、固定数量的数据的容器

属性:容量Capacity、上界limit、位置position、标记mark

操作:存put、取get

  访问io中的数据需要通过Buffer进行操作

  通道:Channel

网络数据通过channel读取、写入

  多路复用器Selector:

NIO编程基础,提供了选择已经就绪的任务的能力,轮询注册在其上的Channel,某个通道发生读、写事件,该通道便处于就绪状态,被selector轮询出来,后通过 SelectionKey 可以获取就绪 Channel 的集合,进行后续的 I/O 操作。

阻塞与非阻塞

进程访问数据时,数据是否准备就绪的一种处理方式

  没有准备时:

     阻塞:等待缓存区中的数据准备好才处理其他事情

     非阻塞:进程访问、未准备好,返回不等,有数据也返回

同步于异步:基于应用程序和操作系统处理IO时间锁

  同步:直接参与IO读写操作,阻塞在某个方法上等待IO时间完成

    对线程的性能

IO事件的轮询:多路复用技术(select模式)

    读写事件交给单独线程处理,完成IO事件的注册功能、同时不断去轮询读写缓冲区(是否有数据准备好)通知相应读写线程,之前的读写线程可以做其他的事情,但是阻塞select线程

 

     client          

               select管家       

             Boss               

客人来 ,对管家说:我来了 

 管家得到这个注册信息后  对boss说:我这里有一个、多个客人  boss你去给A这件东西、给B哪个东西(此时客人可以去做自己的事情)

管家知道boss给他任务后,就会根据注册信息 找对应的客人, 告诉他boss给他*东西

 

  异步:

所有IO读写交给操作系统去处理,处理完给应用程序一个通知

JavaIO模式

    BIO:性能开销,java1.4之前

    NIO:当前主流 jdk1.4 多路复用技术 select模式 实现IO事件轮询

           同步非阻塞的模式

    AIO:jdk1.7 NIO2 真正的异步

NIO AIO原理

原理基础上serversocket、socket做一个改进

Socket     三次握手(连接性能开销大:减少连接次数)    serversocket

读和写采用抽象的管道:一个TCP连接间抽象、一个TCP可以对应多个管道:减少TCP连接次数

代码:

service:连接

public class NioServiceTest {

    private int blockSize = 4096;
    private ByteBuffer sendBuffer = ByteBuffer.allocate(blockSize);
    private  ByteBuffer receivebuffer = ByteBuffer.allocate(blockSize);
    private Selector selector;
    private int port = 8080;

    public NioServiceTest(int port) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //非阻塞
        serverSocketChannel.configureBlocking(false);
        // 检索与此通道关联的服务器套接字
        ServerSocket serverSocket = serverSocketChannel.socket();
        //绑定ip和端口
        serverSocket.bind(new InetSocketAddress(this.port));
        //打开选择器,找到Selector
        selector = Selector.open();
        // 注册到selector,等待连接
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    //监听
    public void listen() throws IOException {
        while (true){
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> itetor = selectionKeys.iterator();
            while (itetor.hasNext()){
                SelectionKey selectionKey = itetor.next();
                itetor.remove();
                handleKey(selectionKey);
            }
        }
    }

    public void handleKey(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel server = null;// 接受请求
        SocketChannel client = null;
        String reciveText ;
        String sendText;
        int cout =0;
        int flag =0;
        // 测试此键的通道是否已准备好接受新的套接字连接。
        if(selectionKey.isAcceptable()){
            // 返回为之创建此键的通道。
            server= (ServerSocketChannel) selectionKey.channel();
            client = server.accept(); // 接受到此通道套接字的连接。
            client.configureBlocking(false);
            client.register(selector,selectionKey.OP_READ);
        }else if(selectionKey.isReadable()){
            client = (SocketChannel) selectionKey.channel();//获得客户端的channel
            int count = client.read(receivebuffer);//读取服务器发送来的数据到缓冲区中
            if(count>0){
                reciveText = new String(receivebuffer.array(),0,count);
                System.out.println("服务端接收到客户端的信息"+reciveText);
            }
        }else if(selectionKey.isWritable()){
            sendBuffer.clear();//写事件,写之前先清空以备下次读取
            client = (SocketChannel) selectionKey.channel();
            //发送的数据
            sendText = "msg send to client ;" + flag++;
            sendBuffer.put(sendText.getBytes());//写到缓存区
            sendBuffer.flip();//将缓冲区各标志复位,因为向里面put了数据,标志被改变,要想从中读取数据发向服务器,就要复位
            client.write(sendBuffer);
            System.out.println("服务器端发送数据给客户端"+sendText);
        }
    }

    public static void main(String[] args) throws IOException {
        int port = 7080;
        NioServiceTest server = new NioServiceTest(port);
        server.listen();
    }
}

 

client:

public class NioClientTest {

    private static int flag;
    private static int blockSize = 4096;
    private static ByteBuffer sendBuffer = ByteBuffer.allocate(blockSize);
    private static ByteBuffer receivebuffer = ByteBuffer.allocate(blockSize);

    private final static InetSocketAddress serverAddress = new InetSocketAddress("127.0.0.1", 7080);

    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        //打开选择器
        Selector selector = Selector.open();
        socketChannel.register(selector, SelectionKey.OP_CONNECT);
        socketChannel.connect(serverAddress);//连接
        Set<SelectionKey> selectionKeys;
        Iterator<SelectionKey> iterator;
        SelectionKey selectionKey;
        SocketChannel client;
        String receiveText;
        String sendText;

        while (true) {
            selectionKeys = selector.selectedKeys();
            iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                selectionKey = iterator.next();
                if (selectionKey.isConnectable()) {
                    client = (SocketChannel) selectionKey.channel();
                    if (client.isConnectionPending()) {
                        client.finishConnect();
                        System.out.println("客户端完成连接操作");
                        sendBuffer.clear();
                        sendBuffer.put("hello service".getBytes());
                        sendBuffer.flip();
                        client.write(sendBuffer);
                    }
                    client.register(selector, SelectionKey.OP_READ);
                }
                if (selectionKey.isReadable()) {
                    client = (SocketChannel) selectionKey.channel();
                    receivebuffer.clear();
                    int count = client.read(receivebuffer);
                    if (count > 0) {
                        receiveText = new String(receivebuffer.array(), 0, count);
                        System.out.println("客户端接收到服务端的数据" + receiveText);
                        client.register(selector, SelectionKey.OP_WRITE);
                    }
                }
                if (selectionKey.isWritable()) {
                    sendBuffer.clear();
                    client = (SocketChannel) selectionKey.channel();
                    sendText = "msg send to server" + flag++;
                    sendBuffer.put(sendText.getBytes());
                    sendBuffer.flip();
                    client.write(sendBuffer);
                    System.out.println("客户端发送数据给服务端"+sendText);
                    client.register(selector,SelectionKey.OP_READ);
                }
            }
            selectionKeys.clear();
        }
    }

}

 

AIO:

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值