ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

linux笔记归纳23:五种IO模型与非阻塞IO

linux笔记归纳23:五种IO模型与非阻塞IO 五种IO模型与非阻塞IO目录五种IO模型与非阻塞IO一、五种IO模型1.1.IO效率问题1.2.五种IO模型1.3.同步与异步1.4.阻塞IO1.5.非阻塞IO1.6.信号驱动IO1.7.多路转接1.8.异步IO二、非阻塞IO2.1.fcntl函数2.2.实现阻塞与非阻塞读取一、五种IO模型1.1.IO效率问题IO 等待 拷贝read() → Input缓冲区 → 等待 拷贝write()→ Output缓冲区 → 等待 拷贝单位时间内传递的数据量越大IO效率越高等待时间久单位时间拷贝量少IO效率降低高效IO单位时间内减少IO中等待的比重1.2.五种IO模型钓鱼 等鱼上钩 提鱼进桶 IO人 进程鱼 数据鱼竿 网络套接字河 操作系统 桶 用户缓冲区张三专注钓鱼鱼漂不动他也不动阻塞IO李四不会因为鱼没有上钩而卡在检测鱼漂上非阻塞IO王五在鱼竿顶部装上铃铛鱼上钩反向通知我信号驱动IO赵六拉一卡车的鱼竿共100只在岸边来回等待多路复用/多路转接田七发起钓鱼过程让其他人钓鱼自己干自己的事情异步IO阻塞 VS 非阻塞IO条件不具备阻塞就会卡住直到条件就绪IO条件不具备非阻塞检测到后会出错返回在钓鱼效率上两者没有任何区别而非阻塞做了其他工作效率才高但IO效率一样谁的IO效率最高站在鱼的角度抬头看 100 / 104 个鱼竿是赵六的单位时间内等的比重很低提高了鱼上钩的效率王五是否要等待王五只是不需要检测但他需要参与钓鱼的过程需要提鱼进桶1.3.同步与异步同步IO阻塞、非阻塞、信号驱动、多路复用异步IO异步IO同步 VS 异步IO 等待 拷贝同步IO参与IO等待或者拷贝的任意一个或多个阶段异步IO只发起IO但IO的工作流与自身工作流无关线程同步 VS IO同步线程同步多执行流执行具有一定顺序性IO同步该执行流是否参与IO的任意过程1.4.阻塞IO在内核将数据准备好之前系统调用一直等待所有的套接字默认都是阻塞方式1.5.非阻塞IO如果内核数据没有准备好系统调用会直接返回EWOULDBLOCK错误码非阻塞IO往往需要以循环的方式反复地尝试读写文件描述符也称为非阻塞轮询1.6.信号驱动IO内核将数据准备好时使用SIGIO信号通知应用程序进行IO操作1.7.多路转接能够同时等待多个文件描述符的就绪状态传统接口read/write/recv/send/recvfrom/sendto......既负责等待又负责拷贝select专门负责等待数据准备好后再调用read/write/recv/send/recvfrom/sendto......拷贝select允许一次等待多个文件描述符1.8.异步IO由内核在数据拷贝完成时通知应用程序二、非阻塞IO2.1.fcntl函数作用设置一个文件描述符的属性cmd F_DUPFD复制一个现有的描述符cmd F_GETFD/F_SETFD获得/设置文件描述符标记cmd F_GETFL/F_SETFL获得/设置文件状态标记cmd F_GETOWN/F_SETOWN获得/设置异步IO所有权cmd F_GETLK/F_SETLK获得/设置记录锁2.2.实现阻塞与非阻塞读取阻塞IO#include iostream #include unistd.h int main() { char buffer[1024]; while(true) { ssize_t n read(0, buffer, sizeof(buffer)); if(n 0) { buffer[n - 1] 0; // 去掉回车 std::cout buffer std::endl; } //TODO } }非阻塞IO#include iostream #include cstdio #include unistd.h #include fcntl.h void SetNonBlock(int fd) { int fl fcntl(fd, F_GETFL); if(fl 0) { perror(fcntl); return; } fcntl(fd, F_SETFL, fl | O_NONBLOCK); // 将fd设置为非阻塞 } int main() { SetNonBlock(0); char buffer[1024]; while(true) { // Linux中ctrl d表示读取结束, read返回值是0, 类似读到文件结尾 ssize_t n read(0, buffer, sizeof(buffer)); if(n 0) { buffer[n - 1] 0; // 去掉回车 std::cout buffer std::endl; } else if(n 0) { if(errno EAGAIN || errno EWOULDBLOCK) // 错误码 { // 1. 底层数据没有准备好 std::cout 数据还未准备好...... std::endl; sleep(1); // TODO continue; } else if(errno EINTR) { // 2. 读取被信号中断 continue; } else { // 3. 读取出错 } } else { break; } // sleep(1); // std::cout . : n std::endl; // C也有语言层缓冲区需要进行刷新才能打印 // TODO } }
返回列表