java的IO

270 阅读2分钟

4种IO模型

BIO

public class BioSocketClient {
    public static void main(String[] args) throws InterruptedException {
        for (int times = 0; times < 10; times++) {
            Thread thread = new Thread(() -> {
                Socket socket;
                try {
                    socket = new Socket("127.0.0.1", 9000);
                    OutputStream outputStream = socket.getOutputStream();
                    StringBuilder data = new StringBuilder();
                    for (int i = 1; i < 1000; i++) {
                        data.append(i).append(";");
                    }
                    outputStream.write(data.toString().getBytes());
                    outputStream.flush();
                    socket.shutdownOutput();
                    byte[] bytes = new byte[1024];
                    InputStream inputStream = socket.getInputStream();
                    int read;
                    if ((read = inputStream.read(bytes)) != -1) {
                        System.out.println("从服务端获取数据:" + new String(bytes, 0, read));
                    }
                    socket.shutdownInput();
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
            thread.start();
        }
    }
}
public class BioSocketServer {

    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("server接受了请求");
            Thread thread = new Thread(() -> {
                //阻塞,等待client连接
                try {
                    handle(socket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
            thread.start();
        }
    }

    private static void handle(Socket socket) throws IOException {
        byte[] bytes = new byte[1024];
        InputStream inputStream = socket.getInputStream();
        int read;
        while ((read = inputStream.read(bytes)) != -1) {
            System.out.println("接收到客户端的数据:" + new String(bytes, 0, read));
        }
        socket.shutdownInput();
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("来自server的回复".getBytes());
        outputStream.flush();
        socket.shutdownOutput();
    }
}

多个客户端发来消息,服务端开启多个线程来处理链接。

NIO

NIO三大组件:channel,buffer,selector。如图所示,端与端通过channel通信。buffer作为缓冲区,提供了高效读写的作用。

image.png

channel

BIO使用流来读写数。如下

Socket socket = new Socket("127.0.0.1",9000);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("***".getBytes());

NIO通过channel来读写数据。channel就是下面那个东西,大家都成为管道。NIO中,只需要一条管道就可以读写,不需要建立输入/输出流.每条channel都连接了一个文件描述符

//省略socketChannel是怎么来的
ByteBuffer bufferWriter = ByteBuffer.wrap("Hello client".getBytes());
socketChannel.write(bufferWriter);

常用的channel有

  • FileChannel,用于文件的IO操作
  • DatagramChannel用于UDP的IO操作
  • SocketChannel,用于TCPIO操作
  • ServerSocketChannel,用于TCP连接的监听操作

Selector

大家叫他选择器。这家伙一出来,就知道,NIO是多路复用IO的实现. 对BIO而言,没有数据到来时,程序阻塞。有数据到来就读数据。 但NIO没有阻塞,他不知道什么时候被连接了,也知道数据什么时候到来。应用程序当然可以主动操作channel读数据,但不一定成功。所以需要告知应用程序,有事件来了。每个通道可以向selector订阅自己感兴趣的事件。java抽象出了如下四个事件

  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE
    //客户端订阅连接事件,selector才会告诉应用程序,已经连接上了服务端
    socketchannel.register(selector, SelectionKey.OP_CONNECT);
    //服务端订阅接收事件,有连接到来,应用程序可以获取到此事件
    serverSocketChannel.register(selecor, SelectionKey.OP_ACCEPT);
    //向selector订阅读事件,有消息来了,selector回通知应用程序去读数据
    socketchannel.register(this.selector,SelectionKey.OP_READ);
    //写事件,意味着buffer未满,可以写入。一般情况下,需要写数据时,才注册写事件,获取到写事件通知,再写数据。然后注销写事件,防止不断收到写事件。
    

buffer

线程不安全

8种类型:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer

三个属性

image.png

属性说明
capacity能够写入缓冲区的对象数量
limit读写的末尾位置
position读写的起始位置
mark标记一个位置,让position回到mark位