IT袋

当前位置:主页 > 经验教程 > 系统教程 >

Linux

Linux I/O模型详解

时间:2024-01-14 17:25:08 来源:IT袋 作者:马勇
导读:Linux,IT袋网网为你介绍Linux方面的知识,继续往下看吧! 先抛出一个问题,基于此问题引出文章的主题:1999 年 Dan Kegel 在其个人站点提出了 C10K问题,首字母 C 是 Client 的缩写

Linux

IT袋网网为你介绍Linux方面的知识,继续往下看吧!

先抛出一个问题,基于此问题引出文章的主题:1999 年 Dan Kegel 在其个人站点提出了 C10K问题,首字母 C 是 Client 的缩写,C10K 即单机同时处理 1 万个连接的问题。

C10K 表示处理 10000 个并发连接,注意这里的并发连接和每秒请求数不同,虽然它们是相似的,每秒处理许多请求需要很高的吞吐量(快速处理它们),但是更大数量的并发连接需要高效的连接调度,即 I/O 模型的问题。

Linux

道听途说:早期 QQ 也面临 C10K 问题,所以他们使用 UDP 绕开了这个问题。

UDP 协议是无连接方式的协议,它的效率高,速度快,占资源少,但是其传输机制为不可靠传送,必须依靠辅助的算法来完成传输控制。

BIO

BIO(Blocking I/O)是最传统的 I/O 模型,它是阻塞的,即在进行 I/O 操作时,转到内核空间处理,应用程序会被阻塞,直到操作完成。

对于每个连接或文件,通常需要创建一个单独的线程或进程来处理,这会导致资源消耗很高。

BIO 不适用并发量大的应用,因为每个 I/O 请求都会阻塞进程,所以,需要为每请求分配一个处理进程(线程)以及时响应,系统开销大。

基于 BIO 去解决 C10K 问题,就需要创建 1 万个进程(线程),这显然是不现实的,系统无法支撑如此庞大的开销。

而且进程(线程)间的频繁切换,也会导致性能的严重下降,系统的绝大部分资源都用来做进程(线程)的上下文切换。

下面是一段服务端基于 BIO 的实现,每一个 Client 都会创建一个线程来处理该连接:

public void serverStartBIO() {
  // 创建服务端Socket, 监听8080 端口
  ServerSocket server = new ServerSocket(8080);
  while (true) {
    // 阻塞等待 Client 连接
    Socket client = server.accept(); 
    // 退出阻塞代表有客户端连接进来
    new Thread(new Runnable(){
      public void run() {
        InputStream in = client.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        while(true){
          // 阻塞等待客户端发送消息
          String dataline = reader.readLine(); 
          if(null != dataline){
              // 读取数据成功
          }else{
              // 关闭客户端
              client.close();
          }
        }
        System.out.println("客户端断开");
      }
    }).start();
  }
}

NIO

NIO 是一种相对于 BIO 更高效的 I/O 模型,它引入了通道(Channel)和缓冲区(Buffer)的概念,允许应用程序进行非阻塞 I/O 操作。

NIO 解决了 BIO 需要大量进程(线程)造成资源浪费的问题,它允许程序在进行 I/O 操作时继续执行其他任务,而不必等待操作完成。它基于以下几个关键概念:

相关阅读