IO

1.IO模型

1.1 BIO

同步并阻塞。服务器实现一个连接一个线程,客户端在有连接请求时服务器启动一个线程处理,没处理完不能做其他操作。
适用于连接数目小且固定的架构。

  • 面向流,只能单向读写,没有数据时会挂起线程阻塞等待,需要对每个连接新建线程处理
  • BIOServer
public class BIOServer {
    /**
     * Server启动 client01启动 client02启动(被阻塞,01输入之后开始连接)
     * @param args
     */
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            serverSocket = new ServerSocket(8000);
            System.out.println("8000");
            while (true){
                //等待客户端连接
                socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress());
                inputStream = socket.getInputStream();
                byte[] bytes = new byte[1024];
                int len = 0;
                //读取客户端数据
                while ((len = inputStream.read(bytes)) >0 ){
                    System.out.println(new String(bytes, 0, len));
                }
                //向客户端写数据
                outputStream = socket.getOutputStream();
                outputStream.write("Hello BIO".getBytes(StandardCharsets.UTF_8));

            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 多线程启动
     */
    public void BIOThreadServer(){
        try {
            ServerSocket serverSocket = new ServerSocket(8000);
            System.out.println("8000");
            while (true){
                //等待客户端连接
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress());
                //多线程
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        InputStream inputStream = null;
                        OutputStream outputStream = null;
                        try {
                            inputStream = socket.getInputStream();
                            byte[] bytes = new byte[1024];
                            int len = 0;
                            //读取客户端数据
                            while ((len = inputStream.read(bytes)) >0 ){
                                System.out.println(new String(bytes, 0, len));
                            }
                            //向客户端写数据
                            outputStream = socket.getOutputStream();
                            outputStream.write("Hello BIO".getBytes(StandardCharsets.UTF_8));

                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                });
                 thread.start();
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 线程池
     */
    public void BIOThreadPool(){
        //线程池
        ExecutorService executorService = Executors.newFixedThreadPool(30);
        try {
            ServerSocket serverSocket = new ServerSocket(8000);
            System.out.println("8000");
            while (true){
                //等待客户端连接
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress());
                //多线程
                executorService.execute( new Thread(new Runnable() {
                    @Override
                    public void run() {
                        InputStream inputStream = null;
                        OutputStream outputStream = null;
                        try {
                            inputStream = socket.getInputStream();
                            byte[] bytes = new byte[1024];
                            int len = 0;
                            //读取客户端数据
                            while ((len = inputStream.read(bytes)) >0 ){
                                System.out.println(new String(bytes, 0, len));
                            }
                            //向客户端写数据
                            outputStream = socket.getOutputStream();
                            outputStream.write("Hello BIO".getBytes(StandardCharsets.UTF_8));

                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }));
            }
        } catch (Exception e){
            e.printStackTrace();
        }

    }
}
  • BIOClient
public class BIOClient01 {
    public static void main(String[] args) throws Exception{
        Socket socket = new Socket("127.0.0.1",8000);
        //字节流
        OutputStream outputStream = socket.getOutputStream();
        //IO方式发送到服务器
        System.out.println("连接成功");
        String str = new Scanner(System.in).nextLine();
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }
}

1.2 NIO

同步非阻塞。服务器实现一个连接一个线程,客户端发送的请求注册到多路复用器上,轮询到有IO请求才启动线程处理。
适合连接数目多且连接短的架构。

  • 面向缓冲,可以双向读写,进行多路复用,一个线程监听多个连接
  • 通道:Channel通过它读写数据,数据先写入缓冲区,再将其写入channel,再从channel读到缓冲区
  • 选择器:Selector,channel注册到selector中
  • 缓冲区:Buffer
  • NIOServer
public class NIOServer {
    public static void main(String[] args) throws Exception{
        //service端的Channel 监听端口
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //非阻塞
        serverSocketChannel.configureBlocking(false);
        //赋值端口
        serverSocketChannel.bind(new InetSocketAddress(8000));
        // 绑定的地址
        System.out.println(serverSocketChannel.getLocalAddress());

        //声明Selector选择器
        Selector selector = Selector.open();
        //注册
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        //轮询 客户端连接就取出来channel
        while (true) {
            int select = selector.select();
            if (select == 0){
                continue;
            }
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                //连接客户端和服务端
                SelectionKey key = iterator.next();
                //判断状态
                if (key.isAcceptable()){
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    //客户端对应的Channel
                    SocketChannel socketChannel = channel.accept();
                    System.out.println(socketChannel.getRemoteAddress());
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }
                if (key.isReadable()){
                    SocketChannel channel = (SocketChannel) key.channel();
                    //想读要先写到buffer
                    channel.read(byteBuffer);
                    String request = new String(byteBuffer.array()).trim();
                    byteBuffer.clear();
                    System.out.println(request);
                    String response = request;
                    channel.write(ByteBuffer.wrap(response.getBytes(StandardCharsets.UTF_8)));
                }
                iterator.remove();
            }
        }
    }
}
  • NIOClient
public class NIOClient {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("127.0.0.1",8000);
        OutputStream outputStream = socket.getOutputStream();
        while (true){
            byte[] bytes = new Scanner(System.in).nextLine().getBytes(StandardCharsets.UTF_8);
            outputStream.write(bytes);
        }
    }
}

1.3 AIO

异步非阻塞。服务器一个有效请求一个线程,客户端请求由操作系统完成后通知服务器启动线程。
适用于连接数目多且长的架构

1.4 Netty

  • 提供异步事件驱动的网络应用程序框架和工具,用以快速开发高性能,高可靠的网络服务器和客户端程序。

  • 基于NIO的客户服务器框架,快速开发网络应用

  • NettyServerHandler

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();
        String request = (String) msg;
        String response = request;
        ctx.write(response);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress());
    }
}
  • NettyServer
public class NettyServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup boosGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boosGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new StringDecoder());
                            pipeline.addLast("encoder", new ObjectEncoder());
                            pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

                            pipeline.addLast(new NettyServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
        } catch (Exception e){

        }
    }
}

1.5 信号驱动IO

1.6 IO多路转接

2.Java IO流

2.1 字符流:字符为单位,16位数据 char

  • 节点流Reader
/**
 * 节点流
 */
public void NodeStream() throws Exception{
    int num = 0;
    //必须存在 read()自动吧char转化为int
    FileReader fileReader = new FileReader("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test.txt");
    
    //第一种
    char[] buf = new char[1024];
    while ((num = fileReader.read(buf)) != -1) {
        System.out.print((new String(buf,0,num)));
    }
    //第二种
    while ((num = fileReader.read()) != -1) {
        System.out.print((char)num);
    }
}
  • 处理流Reader
/**
 * 处理流
 */
public void handlerStream() throws Exception{
    String[] bufString = new String[1024];
    int num = 0;
    FileReader fileReader = new FileReader("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test.txt");
    BufferedReader bufferedReader = new BufferedReader(fileReader);
    String line = null;
    //readLine 单行读取
    while ((line = bufferedReader.readLine()) != null){
        bufString[num] = line;
        num++;
    }
    bufferedReader.close();
    for (int i = 0; i < num; i++){
        System.out.println(bufString[i]);
    }
}
  • 节点流Writer
/**
 * 节点流写入
 * @throws Exception
 */
public void nodeStreamWriter() throws Exception{
    File file = new File("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test.txt");
    //true代表追加 不写就覆盖文件
    FileWriter fileWriter = new FileWriter(file, true);
    // \n换行
    String str = "\nLWX一二三";
    fileWriter.write(str);
    fileWriter.close();
}
  • 处理流Writer
/**
 * 处理流Writer
 * @throws Exception
 */
public void handlerStreamWriter() throws Exception{
    File file = new File("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test.txt");
    //true代表追加 不写就覆盖文件
    FileWriter fileWriter = new FileWriter(file, true);
    BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
    String str = "\n一二三LWX";
    bufferedWriter.write(str);
    bufferedWriter.close();
}

2.2 字节流:字节为单位,8位 byte

  • 节点流
/**
 * 节点流
 */
public void nodeReader() throws Exception {
    FileInputStream fileInputStream = new FileInputStream("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test.txt");
    FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test1.txt");

    byte[] bytes = new byte[fileInputStream.available()];
    //读取到数组
    fileInputStream.read(bytes);
    fileOutputStream.write(bytes);
    fileInputStream.close();
    fileOutputStream.close();

}
  • 处理流
/**
 * 处理流
 * @throws Exception
 */
public void handlerStream() throws Exception{
    FileInputStream fileInputStream = new FileInputStream("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test.txt");
    BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
    FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\lwx20\\Desktop\\Java\\Foundation\\IO\\test1.txt");
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

    //循环输出
    int i;
    while ((i = bufferedInputStream.read()) != -1){
        bufferedOutputStream.write(i);
    }

    bufferedInputStream.close();
    bufferedOutputStream.close();
}

2.3 流的方向

  • 输出流
  • 输入流

2.4 角色

  • 节点流:直接与数据源相连
  • 处理流:对已经存在的流进行封装,如Buffering缓冲区

2.5 Java NIO

NIO三个部分:Channel通道 Buffer缓冲区 Selector选择区
传统IO基于字节流和字符流,NIO基于通道和缓冲区操作,数据从通道读到缓冲区,或者从缓冲区读到通道。
选择区用于监听多个通道事件

IO面向流,NIO面向缓冲区
IO面向流表示没有被缓存,不能前后移动数据。NIO缓存区可以前后移动数据。NIO是非阻塞的

2.5.1 Channel

双向的。
主要实现有FileChannel DatagramChannel SocketChannel ServerSocketChannel 对应文件IO UDP tcp

2.5.2 Buffer

读写的数据都必须经过buffer

2.5.3 Selector

检测多个注册的通道上是否有事件发生,可以获取事件并进行处理
一个单线程可以管理多个通道,当有事件发生时,才进行处理,不需要都去创建线程,避免线程上下文开销

3.序列化

  • 序列化:二进制形式保存在硬盘上,不保存静态变量
  • 反序列化: 二进制文件转化为对象读取

3.1 Serializable接口

  • SerialVersionUID: 接口默认生成,默认生成在反序列化时可能会导致InvaildClassException异常(序列化与反序列化比对通过UID进行,反序列化之前修改类,就会报错)
  • static final long SerialVersionUID =
posted @ 2023-08-17 19:49  lwx_R  阅读(6)  评论(0编辑  收藏  举报