BIO和NIO概念入门级


前言

本文主要是让大家简单的了解一下BIO和NIO的相应的一个区别,并编写了两个测试类,大家可以本地编码测试,更好的体会到两个的区别


一、什么是BIO、NIO

阻塞IO:简称BIO,linux中默认所有的socket都是blocking,其特点是进程会一直阻塞,直到数据拷贝完成。
非阻塞IO:简称NIO,其特点是进程会反复调用IO函数,并马上返回,但在数据拷贝的过程中,进行仍然是阻塞的。

二、测试类编写

1.BIO

代码如下(示例):

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class BioService {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true){
            Socket accept = serverSocket.accept();
            System.out.println("accept客户端开始连接");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        handlerData(accept);
                    }catch (Exception e){
                        e.printStackTrace();
                    }

                }
            }).start();
        }
    }

    private static void handlerData(Socket socket) throws IOException {
        byte[] bytes = new byte[1024];
        System.out.println("开始读取数据");
        //接收客户端的数据,阻塞方法,没有数据可读时就阻塞线程
        int read = socket.getInputStream().read(bytes);
        System.out.println("read 读取数据完毕");
        if (read!=-1){
            System.out.println("接收到客户端发送的数据:" + new String(bytes,0,read));
        }
    }
}

2.NIO测试类

代码如下(示例):

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Niosocket {
    //客户端连接保存队列
    static List<SocketChannel> socketChannelsList = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        //创建NIOServerSocketChannel与BIO的serverSocket类似
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //创建访问端口
        serverSocketChannel.socket().bind(new InetSocketAddress(90000));
        //设置serversocketChannel为非阻塞
        serverSocketChannel.configureBlocking(false);
        System.out.println("serverSocketChannel启动成功");
        while (true) {
            //非阻塞模式accept方法不会阻塞,其他的会阻塞
            //NIO的非阻塞是由系统内部实现的,底层调用了linx内核的accept函数
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (socketChannel != null) {
                System.out.println("客户端连接成功");
                //设置socketChannel为非阻塞模型
                socketChannel.configureBlocking(false);
                //保存客户端放在集合中
                socketChannelsList.add(socketChannel);
            }
            //遍历队列数据 注:必须用遍历器遍历,因为后续需要断开连接
            Iterator<SocketChannel> iterator = socketChannelsList.iterator();
            while (iterator.hasNext()) {
                SocketChannel socket = iterator.next();
                ByteBuffer allocate = ByteBuffer.allocate(128);
                int readData = socket.read(allocate);
                if (readData > 0) {
                    System.out.println("接收到客户端数据:" + new String(allocate.array()));
                } else if (readData == -1) {
                    iterator.remove();
                    System.out.println("客户端断开连接");
                }
            }

        }
    }
}

2.多路复用IO测试类

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class NiosocketService {
    //客户端连接保存队列
    static List<SocketChannel> socketChannelsList = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        //创建NIOServerSocketChannel与BIO的serverSocket类似
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //创建访问端口
        serverSocketChannel.socket().bind(new InetSocketAddress(90000));
        //设置serversocketChannel为非阻塞
        serverSocketChannel.configureBlocking(false);
        //打开Selector处理Channel,即创建epoil
        Selector selector = Selector.open();
        //把ServerSocketChannel注册到selector上,并且selector对客户端accept连接操作感兴趣
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("serverSocketChannel启动成功");
        while (true) {
            //阻塞等待需要处理的事件发生
            selector.select();
            //
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            //获取selector中注册的全部事件的selectionKey实例
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                if (key.isAcceptable()){
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    SocketChannel accept = channel.accept();
                    accept.configureBlocking(false);
                    SelectionKey register = accept.register(selector, SelectionKey.OP_READ);
                    System.out.println("客户端连接成功");
                }else if (key.isReadable()){
                    SocketChannel channel = (SocketChannel) key.channel();
                    ByteBuffer allocate = ByteBuffer.allocate(128);
                    int read = channel.read(allocate);
                    //如果有数据则把他打印出来
                    if (read>0){
                        System.out.println("接收到客户端信息:" + new String(allocate.array()));
                    }else if (read==-1){//如果客户端断开连接,关闭socket连接
                        System.out.println("客户端断开连接");
                        channel.close();
                    }

                }
                iterator.remove();
            }

        }
    }
}

2.本地调试步骤

1.电脑键盘window+R 呼出控制台
2.输入cmd 打开黑窗口
3.建立客户端连接,在黑窗口中输入telent localhost 9000
4.发送你要发送的信息,例如: send helloword
5.这时候你可以在代码控制台收到的信息 helloword

总结

以上就是今天要讲的内容,本文仅仅简单介绍了BIO和NIO的使用,如果大家有不理解的或者需要更改的大家可以私信或者评论

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值