IO模型、select()和pselsect()、poll()和ppoll()函数

一、IO模型

IO的方式有阻塞IO、非阻塞IO、IO复用、信号驱动、异步IO等。
1、阻塞IO
阻塞IO是最通用的IO类型,在数据未到来之前程序会一直等待。
在这里插入图片描述
2、非阻塞IO
把套接字设置成非阻塞的IO,则对每次请求内核都不阻塞,会立即返回。当没有数据的时候会返回一个错误。
在这里插入图片描述
3、IO复用
IO复用模型可以在等待的时候加入超时的时间,当超市时间没有达到的时候与阻塞的情况一致。而超时时间达到仍没有数据,系统会返回,不再等待。
在这里插入图片描述
4、信号驱动IO模型
在进程开始的时候注册一个信号处理的回调函数,进程继续执行,当信号发生时,即有了IO的时间,这里就有数据到来,利用注册的回调函数将到来的数据接收。
在这里插入图片描述
4、异步IO模型
异步IO与信号驱动IO类型,区别在于异步IO在数据复制完成的时候才发生信号通知注册的信号处理函数。
在这里插入图片描述

二、select()和pselect()

函数select()和pselsect()用于IO复用,监视多个文件描述符的集合,判断是否有符合条件的时间发生。select()和pselect()允许程序监视多个文件描述符,当一个或者多个监视的文件描述准备就绪,可以进行IO操作的时候返回。
1、select()

    struct timeval
    {
        time_t  tv_sec;//秒
        long    tv_usec;//微秒 1/1000000s
    };
    #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, timeval* timeout);
  • nfds:比所有文件描述符集合中的文件描述符的最大值大1。
  • readfds:文件描述符集合,监视文件集中任何文件是否有数据可读。函数返回时,将清除其中不可读的文件描述符,只留下可读的文件描述符。
  • writefds:文件描述符集合,监视文件集中任何文件是否有数据可写。函数返回时,将清除其中不可写的文件描述符,只留下可写的文件描述符。
  • exceptfds:文件描述符集合,监视文件集中任何文件是否发生错误
  • timeout:设置select()所监视的文件集合中的事件没有发生时,最长的等待时间,超过此时间函数会返回。当超时时间设为NULL,表示阻塞操作会一直等待直至符合条件。当timeout为0,则会立刻返回。

select()返回值为0,-1或者大于0的整数值:当监视的文件集中有文件描述符符合要求则返回大于0的正值;超时时返回0;错误时返回-1。errno如下:
在这里插入图片描述
当不需要监视某种文件时,将对应的文件集设为NULL。如果所有文件集合均为NULL,则表示等待一段时间。
操作文件描述集合的宏:

  • FD_ZERO():清理文件描述符集合
  • FD_SET():向某个文件描述符集合中加入文件描述符
  • FD_CLR():从某个文件描述符集合中取出某个文件描述符。
  • FD_ISSET():测试某个文件描述符是否某个集合中的一员
    文件描述符集合存在最大的限制,最大值为FD_SETSIZE。

示例:

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int main( ) 
{
fd_set rd;//读文件集合
    //监视标准输入是否可以读数据
    FD_ZERO(&rd);
    FD_SET(0,&rd);//

    timeval tv;//时间间隔
    tv.tv_sec = 5;//5s超时等待
    tv.tv_usec = 0;
    int err = select(1,&rd,NULL,NULL,&tv);

	if (err == -1)						//出错
		perror("select()");
	else if (err)						//标准输入有数据输入,可读
		printf("Data is available now.\n");//FD_ISSET(0, & rd) 的值为真
	else
		printf("No data within five seconds.\n");//超时,没有数据到达
	return 0;
}

2、pselelct()

    struct timespec
    {
        long tv_sec;//秒
        long tv_nsec;//纳秒
    };
    #include <sys/select.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    int pselect(int nfds,fd_set* readfds, fd_set* writefds,
                fd_set* exceptfds,const timespec* timeout,const sigset_t* sigmask);
  • sigmask:信号掩码
    select()是用一种超时轮询的方式来查看文件的读写错误可操作性。pselect()与其类似,区别如下:
  • 超时的时间结构是纳秒级结构。
  • 增加了进入pselect()函数时替换掉的信号处理方式,当sigmask为NULL时与select的方式一致。
  • select()函数在执行后可能会改变timeout的值,改为还剩多少时间,而pselect()不会。

示例:

int child_events = 0;
void child_sig_handler(int x)//信号处理函数
{
	child_events++;//调用次数+1
	signal(SIGCHLD,child_sig_handler);//重设定信号回调函数
	return;
}
int main()
{
	//设定的信号掩码喝原始信号掩码
	sigset_t sigmask, orig_sigmask;
	sigemptyset(&sigmask);//清空信号
	sigaddset(&sigmask,SIGCHLD);//将SIGCHLD加入sigmask
	//设定信号SIG_BLOCK的掩码sigmask,并将原始掩码保存到orig_sigmask中
	sigprocmask(SIG_BLOCK,&sigmask,&orig_sigmask);
	//挂接对信号处理函数
	signal(SIGCHLD,child_sig_handler());
	//主循环
	while(1)
	{
		for(;child_events >0;child_events--)
		{
		//处理动作
		}
	}
	//pselect IO复用
	int r = pselect(nfds,&fd,&wd,&er,0, &orig_sigmask);
	//主程序
	
}

三、poll()和ppoll()

与select()完成相似的功能。
1、poll()

struct pollfd
{
	int fd;//文件描述符
	short events;//请求的事件
	short renvent;//返回的事件
};
#include <poll.h>
int poll(pollfd* fds,nfds_t nfds,int timeout);

poll()函数监视在fds数组指明的一组文件描述符上发生的动作,当满足条件或超时的时候会退出。

  • fds:指向结构pollfd数组的指针,监视的文件描述符和条件放在里面。
  • nfds:比监视的最大描述符的值大1
  • timeout:超时时间,单位毫秒,负值表示永远等待。
  • pollfd结构中events和revents的值及含义如下:
  • 在这里插入图片描述

poll()返回值:大于0表示成功,返回值为满足条件的文件描述符数量;0表示超时;-1表示发生错误,errno如下:
在这里插入图片描述

2、ppoll()

#include <poll.h>
int ppoll(pollfd* fds,nfds_t nfds,
		  const timespec* timeout,const sigset_t* sigmask);

与poll()区别:

  • 超时时间采用了纳米级的变量
  • 可以在ppoll函数的处理过程中挂接临时的信号掩码。

四、非阻塞编程

非阻塞方式的操作是 函数调用立刻返回,不管数据是否成功读取或成功写入。使用fcntl()将套接字文件描述符按照如下代码进行设置后,可以进行非阻塞的编程:

fcntl(fd,F_SETFL,O_NONBLOCK);

其中fd是套接字的文件描述符,使用F_SETFL命令将套接字fd设置为非阻塞方式后,再进行读写操作就可以马上返回了。

注:

LINUX网络编程 第二版 第九章 读书笔记

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值