1、阻塞IO
2、非阻塞IO
3、IO多路复用
4、信号驱动IO
5、异步IO(AIO)
这里有必要知道,在socket编程中网络数据是如何被处理及传输的,以read操作为例,首先应用程序会告知内核要开始进行读操作,内核接到命令后会先创建文件描述符(file descriptor),等数据从网络传输到本地,经过网络层的包解析后得到真正的数据,此时内核会将数据缓存在文件描述符的读缓冲区中,因为文件描述符由内核创建,所以这里的缓冲区也是在内核中,最后将该缓冲区中的数据复制到应用程序的缓冲区。write操作也类似。
阻塞IO
缺省状态下,一个套接字建立以后所处的模式就是阻塞IO模式。这种模式比较好理解,直到有数据到达本地系统调用才返回。
非阻塞IO
和阻塞IO相对应,不管有没有数据到达系统调用都立即返回。当应用程序采用非阻塞IO模式时,需要使用一个循环操作来不停地测试文件描述符是否可读,这是一个极度浪费CPU资源的操作。
IO多路复用
IO多路复用是通过调用select或poll函数来实现。和阻塞IO模式相比,把阻塞操作提前,即在调用select或poll时阻塞,后面的真正数据操作并不阻塞。多数复用的高明之处在于它能同时等待多个文件描述符,当文件描述符集中有一个进入就绪状态时,select函数就可以返回。
信号驱动IO
当文件描述符就绪时,内核使用SIGIO信号通知, 这种模式就是信号驱动模式。在这种模式下,系统调用会立即返回,当数据就绪时,系统会发送SIGIO信号。 实现信号驱动IO需要三步:
1、一个信号处理函数来进行IO操作(必须先于2和3操作)
2、设定套接字的拥有者,通过fcntl函数的F_SETOWN参数来实现即fcntl(fd,F_SETOWN,getpid())
3、套接字允许使用异步IO,通过fcntl函数的F_SETFL命令,O_ASYNC为参数来实现即fcntl(fd,F_SETFL,O_ASYNC)
异步IO
在AIO下,只需要告诉内核要进行IO操作,内核会立刻返回,具体的IO操作全部由内核来完成,程序会继续往下执行,当IO操作结束后内核会通知程序。与信号驱动IO相比,内核通知的时间点不同,信号驱动IO是在数据就绪时通知,而AIO是IO操作结束时通知。
fcntl函数
函数声明(manipulate file descriptor)
select函数
函数声明
select函数可以同时监视多个套接字,通过它可以知道哪个套接字可以读取数据,哪个可以写入数据,哪个出现错误。正常返回就绪描述符的数目,0为超时,-1为出错。
nfds是readfds、writefds、exceptfds集合中文件描述符中最大的数字加1
readfds为是否可读的fd集合
writefds为是否可写的fd集合
exceptfds为是否有例外发生的fd集合
结构timeval
当select函数返回时,timeval中的时间被设置为执行select后剩下的时间。
有几点注意:
1、linux的最小时间片是100微秒,如果tv_usec设得过小则毫无意义。
2、timeval为0,select会立即返回
3、timeval为NULL,select进入阻塞状态
select代码示例
2、非阻塞IO
3、IO多路复用
4、信号驱动IO
5、异步IO(AIO)
这里有必要知道,在socket编程中网络数据是如何被处理及传输的,以read操作为例,首先应用程序会告知内核要开始进行读操作,内核接到命令后会先创建文件描述符(file descriptor),等数据从网络传输到本地,经过网络层的包解析后得到真正的数据,此时内核会将数据缓存在文件描述符的读缓冲区中,因为文件描述符由内核创建,所以这里的缓冲区也是在内核中,最后将该缓冲区中的数据复制到应用程序的缓冲区。write操作也类似。
阻塞IO
缺省状态下,一个套接字建立以后所处的模式就是阻塞IO模式。这种模式比较好理解,直到有数据到达本地系统调用才返回。
非阻塞IO
和阻塞IO相对应,不管有没有数据到达系统调用都立即返回。当应用程序采用非阻塞IO模式时,需要使用一个循环操作来不停地测试文件描述符是否可读,这是一个极度浪费CPU资源的操作。
IO多路复用
IO多路复用是通过调用select或poll函数来实现。和阻塞IO模式相比,把阻塞操作提前,即在调用select或poll时阻塞,后面的真正数据操作并不阻塞。多数复用的高明之处在于它能同时等待多个文件描述符,当文件描述符集中有一个进入就绪状态时,select函数就可以返回。
信号驱动IO
当文件描述符就绪时,内核使用SIGIO信号通知, 这种模式就是信号驱动模式。在这种模式下,系统调用会立即返回,当数据就绪时,系统会发送SIGIO信号。 实现信号驱动IO需要三步:
1、一个信号处理函数来进行IO操作(必须先于2和3操作)
2、设定套接字的拥有者,通过fcntl函数的F_SETOWN参数来实现即fcntl(fd,F_SETOWN,getpid())
3、套接字允许使用异步IO,通过fcntl函数的F_SETFL命令,O_ASYNC为参数来实现即fcntl(fd,F_SETFL,O_ASYNC)
异步IO
在AIO下,只需要告诉内核要进行IO操作,内核会立刻返回,具体的IO操作全部由内核来完成,程序会继续往下执行,当IO操作结束后内核会通知程序。与信号驱动IO相比,内核通知的时间点不同,信号驱动IO是在数据就绪时通知,而AIO是IO操作结束时通知。
fcntl函数
函数声明(manipulate file descriptor)
点击(此处)折叠或打开
- #include <unistd.h>
- #include <fcntl.h>
-
- int fcntl(int fd, int cmd, ... /* arg */ ); /*第二个参数是操作命令,如之前提到的设置阻塞非阻塞的命令F_SETFL,设置套接字属主的命令F_SETOWN,第三个参数是命令的参数,如前边提到的O_ASYNC*/
select函数
函数声明
点击(此处)折叠或打开
- #include <sys/select.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <unistd.h>
-
- int select(int nfds, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds, struct timeval *timeout);
-
- void FD_CLR(int fd, fd_set *set); /*将文件描述符fd从集合set中删除*/
- int FD_ISSET(int fd, fd_set *set); /*判断文件描述符fd是否存在于集合set中*/
- void FD_SET(int fd, fd_set *set); /*将fd加入set中*/
- void FD_ZERO(fd_set *set); /*将集合清0*/
nfds是readfds、writefds、exceptfds集合中文件描述符中最大的数字加1
readfds为是否可读的fd集合
writefds为是否可写的fd集合
exceptfds为是否有例外发生的fd集合
结构timeval
点击(此处)折叠或打开
- struct timeval
- {
- int tv_sec; /*秒数*/
- int tv_usec; /*微秒数*/
- }
有几点注意:
1、linux的最小时间片是100微秒,如果tv_usec设得过小则毫无意义。
2、timeval为0,select会立即返回
3、timeval为NULL,select进入阻塞状态
select代码示例
点击(此处)折叠或打开
- /*
- * =====================================================================================
- *
- * Filename: test.c
- * Description: 从stdin等待输入,等待时间1.5秒
- * Version: 1.0
- * Created: 06/21/2012 01:48:47 PM
- * Revision: none
- * Compiler: gcc
- *
- * Author: djstava , djstava@gmail.com
- * Company: ABC Inc
- *
- * =====================================================================================
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/time.h>
-
- #define STDIN 0
-
- int main(int argc,char **argv)
- {
- struct timeval tv;
- fd_set readfds;
-
- tv.tv_sec = 1;
- tv.tv_usec = 500000;
-
- FD_ZERO(&readfds);
- FD_SET(STDIN,&readfds);
-
- select(STDIN+1,&readfds,NULL,NULL,&tv);
-
- if(FD_ISSET(STDIN,&readfds))
- printf("Input from stdin!\n");
- else
- printf("Timed out!\n");
- }