使用java模拟BIO模型

114 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第43天,点击查看活动详情 >>

使用java模拟BIO模型

今天我们来学习BIO模型,在学习的过程中,我们会通过具体的代码例子来来讲解。

什么是BIO模型

BIO模式,又叫同步阻塞模型(blocking i/o),这是一种传统的IO模型,服务器的实现模式为一个连接一个线程,即对于每一个客户端的连接,服务器都会开启一个线程来处理它。

当然啦,因为这是高度专一了,所以如果客户端到来的连接不做任何事情,那么就会给服务器造成额外的线程开销。

BIO的使用场景

BIO模型是比较适合于连接数较少的并且固定的架构中的,因为这种方式对服务器资源要求比较高,在并发场景中受限较大。

用Java代码实现一个BIO模型的服务器:

在真正展示代码之前,我们先来说明一下,这里对服务器的要求:

  1. 服务器中需要启动一个ServerSocket
  2. 客户端对服务器进行通信,默认是一个连接对应服务器中的一个线程
  3. 在客户端的请求被发出后,若服务器有线程响应,则返回;若没有线程响应,则会等待,或者拒接
  4. 如果有响应,客户端线程会等待请求结束后,在继续执行

了解了服务器的需求之后,那么我们就开始动手自己写一个:

简易的BIO服务器,主函数代码如下:

public static void main(String[] args) throws Exception {
        // 创建线程池
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
​
        ServerSocket serverSocket = new ServerSocket(666);
        System.out.println("服务器启动。。。");
​
        while (true) {
            System.out.println("before connect : 线程id = " + Thread.currentThread().getId() + "\t线程名 = " + Thread.currentThread().getName());
            System.out.println("waiting for connect...");
            final Socket acceptSocket = serverSocket.accept();
            System.out.println("连接到一个客户端");
​
            // 创建线程
            newCachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    handle(acceptSocket);
                }
            });
        }
    }

在服务器开启之后,那么剩下的就是等待客户端的连接和读取数据了,下面我们来学习一下相关的方法实现:

    public static void handle(Socket acceptSocket) {
        try {
            System.out.println("线程id = " + Thread.currentThread().getId() + "\t线程名 = " + Thread.currentThread().getName());
            InputStream inputStream = acceptSocket.getInputStream();
            byte[] bytes = new byte[1024];
            // 循环读取数据到 bytes
            while (true) {
                System.out.println("reading...");
                int read = inputStream.read(bytes);
                if (read != -1) {
                    System.out.println("线程id = " + Thread.currentThread().getId() + "\t线程名 = " + Thread.currentThread().getName());
                    System.out.println(new String(bytes, 0, read));
                } else {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println("断开连接");
            try {
                acceptSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

经过了上面两步我们已经完成了一个简易的BIO服务器了,在每个客户端连接到来的时候,服务器都会开启一个线程对其进行处理。

总结:

BIO模型是一种传统的IO模型,在一些固定架构且较小的场景下,更实用;因为如果是在高并发场景下的话,它承受不了那么大的线程开销。