IO 多路复用

上面服务端通过多线程的方式处理客户端请求实现了主线程的非阻塞,使用不同线程处理不同的连接请求,但是我们并没有那么多的线程资源,并且等待读就绪的过程是耗时最多的,那么有没有什么办法可以将连接保存起来,等读已就绪时我们再进行处理。

arr = new Arr[];
listenfd = socket(); // 打开一个网络通信套接字
bind(listenfd); // 绑定
listen(listenfd); // 监听
while(1) {
  connfd = accept(listenfd); // 阻塞 等待建立连接
  arr.add(connfd);
}

// 异步线程检测 连接是否可读
new Tread(){
 for(connfd : arr){
 int n = read(connfd, buf); // 检测 connfd 是否可读
 if(n != -1){
       newThreadDeal(buf); // 创建新线程处理
       close(connfd); // 关闭连接 
       arr.remove(connfd); // 移除已处理的连接
 }
 }
}

newTheadDeal(buf){
  doSomeThing(buf); // 处理数据
}

select

image.png

image.png

arr = new Arr[];
listenfd = socket(); // 打开一个网络通信套接字
bind(listenfd); // 绑定
listen(listenfd); // 监听
while(1) {
  connfd = accept(listenfd); // 阻塞 等待建立连接
  arr.add(connfd);
}

// 异步线程检测 通过 select 判断是否有连接可读
new Tread(){
 while(select(arr) > 0){
 for(connfd : arr){
 if(connfd can read){
 // 如果套接字可读 创建新线程处理
        newTheadDeal(connfd);
        arr.remove(connfd); // 移除已处理的连接
 }
 }
 }
}

newTheadDeal(connfd){
 int n = read(connfd, buf); // 阻塞读取数据
    doSomeThing(buf); // 处理数据
    close(connfd); // 关闭连接 
}

减少大量系统调用但也存在一些问题