BIO、NIO、Netty学习笔记

BIO是阻塞io,是面向数据流的,一个连接对应一个线程。服务端监听指定端口,socket.accept()方法阻塞等待客户端连接。

示例代码如下

package NettyLearn.bio;


import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BIOServer {

    public static void main(String[] args) throws IOException {
        //1.创建线程池
        //2.如果有客户端连接 就创建线程通信
        //3.客户端使用cmd中的telnet建立连接进行测试
        // telnet 127.0.0.1 6666
        //按下 ctrl+]
        //使用send 向服务端发送数据
        ExecutorService e = Executors.newCachedThreadPool();
//        e.execute();
//        Socket socket =new Socket();
        ServerSocket serverSocket =new ServerSocket(6666);
        System.out.println("服务端启动了。。。");
        while (true)
        {
            final Socket socket = serverSocket.accept();
            System.out.println("已连接到一个客户端");
            e.execute(new renwu(socket));
        }
    }

}

class renwu implements Runnable {
    private Socket socket;

    renwu(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        System.out.println("线程的id:"+Thread.currentThread().getId()+
                "线程的名字:"+Thread.currentThread().getName());
        InputStream inputStream = null;
        try {
            inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            while (true) {
                int read = inputStream.read(bytes);
                if (read != -1) {
                    System.out.println(new String(bytes, 0, read));
                }
                else {
                    break;
                }


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


    }
}

上面是一个典型的bio连接的例子,启动多个telnet客户端进程访问服务端,通过打印的线程id和线程name可以发现,一个连接对应一个线程,当socket的inputStream.read()没有数据时,线程也会阻塞,效率低下,造成资源浪费。

而NIO有效的解决了这个问题,NIO面向数据块,采用多路复用的机制,一个线程对应一个Selector,一个Selector对应对多个连接,也就是多个Channel,而每个Channel都对应一个内存块Buffer(底层是数组),Selector会切换到有Event发生的Channel上,因此当Channel没有事件发生时,不会导致线程的阻塞。数据的读写通过对Buffer读写来完成,在读写转换时需要对Buffer执行flip方法进行切换。BIO是单向的,要么是输出流,要么是输入流,而Channel是双向的,可以返回底层操作系统的情况,比如Linux,底层的操作系统通道就是双向的。

Buffer作为NIO的核心,关键的属性有

  1. limit 缓冲区当前终点,不能对缓冲区超过极限的位置进行读写操作,但是极限是可以修改的。
  2. positon  位置,下一个要被读写的元素的索引,每次读写缓冲区数据时都会改变该值,为下次读写作准备。
  3. capacity 容量,即可以容纳的最大数据量,在缓冲区创建时被指定且不能修改。
  4. mark 标记。

NIO的示例代码如下


import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NIOtest1 {

    public static void main(String[] args) throws IOException {
        copyFileBytransferFrom();
    }

    public static  void copyFileBytransferFrom() throws  IOException{
        //通过Channel的transferForm函数实现文件拷贝
        File f1= new File("1.txt");
        File f2= new File("2.txt");

        FileInputStream in = new FileInputStream(f1);
        FileChannel inChannel = in.getChannel();
        FileOutputStream out =new FileOutputStream(f2);
        FileChannel outChannel = out.getChannel();

        //使用transferFrom完成拷贝
        outChannel.transferFrom(inChannel,0,inChannel.size());
        //关闭相关通道和流
        inChannel.close();
        outChannel.close();
        in.close();
        out.close();
    }
    public static void  readFileAndWrite2Another() throws IOException{
        //使用一个buffer实现文件的拷贝
        File f1= new File("1.txt");
        File f2= new File("2.txt");

        FileInputStream in = new FileInputStream(f1);
        FileChannel inChannel = in.getChannel();
        FileOutputStream out =new FileOutputStream(f2);
        FileChannel outChannel = out.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(512);

        while (true){
            int read = inChannel.read(buffer);
            if(read==-1) break;
            buffer.flip();
            outChannel.write(buffer);
            buffer.clear();
        }

        inChannel.close();
        outChannel.close();

    }
    public static void  readFile() throws IOException {
        //本地文件读
        File f= new File("1.txt");

        FileInputStream in = new FileInputStream(f);
        FileChannel channel = in.getChannel();

        ByteBuffer buffer =ByteBuffer.allocate((int) f.length());

        channel.read(buffer);

        buffer.flip();

        System.out.println(new String(buffer.array()));

        channel.close();
    }

    public static void  writeFile() throws IOException {
        //本地文件写 fileChannel
        File f =new File("1.txt");

        FileOutputStream out = new FileOutputStream(f);

        FileChannel channel = out.getChannel();

        ByteBuffer buffer =ByteBuffer.allocate(1024);

        String s ="测试一下NIO";
        buffer.put(s.getBytes());

        buffer.flip();

        channel.write(buffer);

        channel.close();
    }
}

Netty

它是异步、事件驱动的网络应用程序框架和工具。

 

你可能感兴趣的:(BIO、NIO、Netty学习笔记)