Linux的五种I/O模型

一、阻塞IO

应用程序调用IO函数,导致应用程序阻塞,等待数据准备好。如果数据没有准备好,一直等待数据准备好了,从内核拷贝到用户空间,IO函数返回成功指示。

优点:及时返回数据,无延时,方便调试;

缺点:需要付出等待的代价。

二、非阻塞IO

应用程序调用IO函数,并不需要等待,而是马上就得到了一个结果。一旦内核中的数据准备好了,并且又再次收到了请求,那么它马上就将数据拷贝到了用户线程,然后返回。

优点:不用等待任务,当前线程同时处理多任务;

缺点:任务完成的响应延时增大,因为每隔一段时间才去执行询问的动作。

三、IO多路复用(I/O multiplexing

IO多路复用就是在单个线程里,通过跟踪多个IO流的状态来同时管理多个IO流,简单的说就是在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流。Linux下IO多路复用的基本方法包括select、poll、epoll,其中epoll是poll的加强版。

1.select中的主要函数:

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)

返回值:就绪描述符的数目,超时返回0,出错返回-1

设置fd_set的宏:

                 void FD_ZERO(fd_set *fdset);           //清空集合

                 void FD_SET(int fd, fd_set *fdset);   //将一个给定的文件描述符加入集合之中

                 void FD_CLR(int fd, fd_set *fdset);   //将一个给定的文件描述符从集合中删除

                 int FD_ISSET(int fd, fd_set *fdset);   // 检查集合中指定的文件描述符是否可以读写 

使用时注意,每次select要清空并重新设置fd_set

     FD_ZERO(fds);//fds表示需要监测的文件标识符集合
                FD_SET(clientfd, fds);//clientfd表示监测的文件句柄

2.poll中的主要函数:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

fds:指向一个结构体数组的第0个元素的指针,每个数组元素都是一个struct pollfd结构,用于指定测试某个给定的fd的条件

           struct pollfd{
                               int fd;            //文件描述符
                               short events;    //等待的事件
                               short revents;    //实际发生的事件
                               };
           events:指定监测fd的事件(输入POLLIN、输出POLLOUT、错误POLLERR)

           revents:revents 域是文件描述符的操作结果事件,内核在调用返回时设置这个域。events 域中请求的任何事件都可能在 revents                               域中返回.

           监测输入:(fds[0].revents & POLLIN ) == POLLIN  // 标准输入

           3.epoll中的主要函数:

int epoll_create(int size);
 
			返回:若成功返回文件描述符,若出错返回-1
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev);
 
			返回:若成功返回0,若出错返回-1
int epoll_wait(int epfd, struct epoll_event *evlist, int maxevents, int timeout);
 
			返回:成功返回就绪态文件描述符数目,超时返回0,若出错返回-1

          参数ev是指向结构体epoll_event的指针,结构体的定义如下。
          struct epoll_event
                           {
                             uint32_t    events;    /* epoll events(bit mask) */
                             epoll_data_t    data;    /* User data */
                           };
           结构体epoll_event中的data字段的类型为:
           typedef union epoll_data
                          {
                             void        *ptr;    /* Pointer to user-defind data */
                             int        fd;    /* File descriptor */
                             uint32_t    u32;    /* 32-bit integer */
                             uint64_t    u64;    /* 64-bit integer */
                          }epoll_data_t;


四、信号驱动式IO

信号驱动IO是指:进程预先告知内核,使得 当某个socketfd有events(事件)发生时,内核使用信号通知相关进程。

信号驱动IO模型主要是在UDP套接字上使用,在TCP套接字上几乎是没有什么使用的。在UDP上,SIGIO信号会在下面两个事件的时候产生:

1.数据报到达套接字

2.套接字上发上一部错误

因此我们很容易判断SIGIO出现的时候,如果不是发生错误,那么就是有数据报到达了。

而在TCP上,由于TCP是双工的,它的信号产生过于平凡,并且信号的出现几乎没有告诉我们发生了什么事情。因此对于TCP套接字,SIGIO信号是没有什么使用的。

 

 

以上四种都属于同步IO模型,接下来第五种是最常用的异步模型。

五、异步式IO

用户程序可以通过向内核发出I/O请求命令,不用等待I/O事件真正发生,可以继续做另外的事情,等I/O操作完成,内核会通过函数回调或者信号机制通知用户进程。这样很大程度提高了系统吞吐量。

目前比较知名的有 Glibc 的 AIO   与 Kernel Native AIO,Kernel Native AIO 几乎提供了近乎完美的异步方式,但
目前的Kernel AIO 仅支持 O_DIRECT 方式来对磁盘读写,这意味着,你无法利用系统的缓存,同时它要求读写的的大小和偏移要以区块的方式对齐,所以现在Linux 上,没有比较完美的异步IO方案。 (AIO不支持fsync,AIO如果操作socket fd,不会提示错误,但是也会以同步的方式进行。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值