慢慢说IO模型:传统BIO

小Q:什么是 IO 模型?

慢慢:我们先来了解下 IO。在 linux 系统中,一切皆是文件,而文件又是一串二进制流。操作系统中有很多的流,我们需要通过一个符号表才能够管理这些流,这个符号表为 fd,即文件描述符表。

所以,Linux 的内核将所有外部设备都看做一个文件来操作,每一个文件的读写操作都会返回一个 fd。

我们每次操作文件,都需要用户空间,内核空间,设备空间进行紧密的配合。那么如何让他们更高效的配合呢?就提出了多种的设计方案,也叫做 IO 模型。


小Q:能具体讲下 BIO 模型吗?

BIO 模型即同步阻塞模型。我们以网络 IO 模型为例。

网络编程的基本模型是 Client/Server 模型,也就是两个进程间相互通信,其中服务端提供位置信息,客户端通过连接操作向服务端监听的地址发送连接请求,通过三次握手建立连接,如果连接成功,则双方可以通过网络套接字进行通信。

在传统的 BIO 模式下,Server 必须先开启一个线程用来监听是否有连接的请求,每当有连接建立时,通过创建线程去处理该链接,从而保证有一个线程是用来专门监听请求,而不会被业务功能所耽误。


小Q:懂了懂了,赶快上代码吧!

服务端程序

public class Server {
    public static void main(String[] args) {
        ServerSocket server = new ServerSocket(8080);   // 开启服务进程
        Socket socket = null;
        while (true) {  // 此线程循环监听是否有连接请求
            socket = server.accept();   // 这里阻塞,知道有连接请求
            new Thread(new ServerHandler(socket)).start();   // 开启一个线程处理请求
        }
        server.close();   // 关闭服务
        server = null;
    }
}

请求处理

public ServerHandler implements Runnable {
    private Socket socket;
    public ServerHandler (Socket socket) {
        this.socket = socket;
    }
    
    @Override
    public void run() {
        BufferedRead in = null;
        PrintWriter out = null;
        try {
            in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));  // 从 socket 通道中获取请求的数据
            out = new PrintWriter(this.socket.getOuputStream(), true);
            String body = null;
            while (true) {
                body = in.readLine();  // 从缓冲区中读取一行数据
                if (body == null)
                    break;   // 缓冲区中没有数据
                out.println(body);  // 再写入 socket 中,发送给客户端
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {   
            // 优雅退出
            if (in != null) {
                try {
                    in.close();  // 释放缓冲区
                    in = null;
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
                
            }
            if (out != null) {
                out.close();  // 释放缓冲区
                out = null;
            }
            if (this.socket != null) {
                try {
                    this.socket.close();  // 关闭连接
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
                this.socket = null;
            }
        }
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        BufferReader in = null;
        PrintWriter out = null;
        try {
            socket = new Socket("127.0.0.1", 8080);   // 建立连接,发起连接请求
            in = new BufferReader(new InputStreamReader(socket.getInputStream()));  // 监听此缓冲区
            out = new PrintWriter(socket.getOutputStream(), true);
            out.println("QUERY TIME ORDER");   // 向服务器端发送指令
            String s = in.readLine();   // 从缓冲区中获取数据
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 优雅退出
            if (out != null) {
                try {
                    out.close();  // 释放缓冲区
                    out = null;
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
                
            }
            if (in != null) {
                in.close();  // 释放缓冲区
                in = null;
            }
            if (this.socket != null) {
                try {
                    this.socket.close();  // 关闭连接
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
                this.socket = null;
            }
        }
    }
}

小Q:大概理解了,就是用一个线程去监听连接,然后每次有连接都开启一个线程去处理。这样做是不是会有缺陷呀!

慢慢:是的呀。如果突然有大量的请求发到服务器上,那么服务器就得创建大量的线程,这会导致创建资源的不可控,甚至是服务器宕机,这种是绝对不允许的。此外,这种模型也不支持长连接,如果一个连接久久都每释放,那么这个线程就一直被占用,导致后面能创建的线程数变少。


小Q:说到长连接,长连接和短连接的区别是什么呢?

慢慢:短连接的话,每发送完请求并接收到响应后都会自动断开连接。我们都知道,TCP 连接的建立需要经过三次握手,这也导致网络负担的增加,并且握手的数据包往返也消耗了大量的时间。长连接则是通过心跳机制来维护这个连接不会断开,并且每次发送请求都不用经过握手阶段。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慢慢编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值