1、阻塞IO
读阻塞:当对文件描述符进行读操作时,如果没有资源分配则进入阻塞状态。read、recv…
写阻塞:当对文件描述符进行写操作时,如果没有足够空间,则进入阻塞状态。 write、send…
特殊:accept、connect
缺点:当用户使用阻塞IO进行IO操作时,有可能会阻碍其他程序的正常运行
2、非阻塞IO
特点:当使用非阻塞IO,没有资源(输入或者输出)时,IO函数不会阻塞,而是会立即返回
缺点:因为非阻塞IO函数在频繁调用时会消耗大量系统资源
将阻塞IO设置为非阻塞IO的方法:fcntl
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
参数:
fd:文件描述符
cmd:命令
F_GETFL -- 获取文件描述符属性状态的值
F_SETFL -- 设置文件描述符属性状态的值
文件描述符的状态标志,用于表示非阻塞特性 -- O_NONBLOCK
返回值:
根据cmd的不同,会有不同的返回值
例:
1、获取文件描述符对应的属性状态标志
int flags = fcntl(0, F_GETFL, 0);
2、添加非阻塞属性
flags = flags | O_NONBLOCK;
3、设置非阻塞
fcntl(0, F_SETFL, flags);
3、IO多路复用
IO多路可以对用户指定的文件描述符做统一的监测
(1)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);
参数:
nfds:三张监测表中最大的文件描述符的值+1
readfds:读监测表的首地址,如果不进行读监测,可以填NULL
writefds:写监测表的首地址,如果不进行写监测,可以填NULL
exceptfds:异常监测表的首地址,如果不进行异常监测,可以填NULL
timeout:设置的超时时间的首地址,如果不设置超时时间,可以填NULL
返回值:
成功返回三个文件描述符监测表中的监测文件个数,失败返回-1,如果返回0表示超时
//删除文件描述符
void FD_CLR(int fd, fd_set *set);
//判断文件描述符是否有响应
int FD_ISSET(int fd, fd_set *set);
//添加文件描述符
void FD_SET(int fd, fd_set *set);
//清空监测表
void FD_ZERO(fd_set *set);
超时时间类型的结构体
struct timeval {
long tv_sec; /* seconds */ 秒
long tv_usec; /* microseconds */ 微秒
};
例:
struct timeval mytime;
mytime.tv_sec = 5;
mytime.tv_usec = 0;
select监测流程:
int sockfd =scoket();
1、创建监测表,初始化监测表(清0)
fd_set rfds;
FD_ZERO(&rfds);
2、向监测表中添加文件描述符
FD_SET(sockfd, &rfds);
3、循环监测表 -- select
int max_fd = fd+1;
while(1)
{
ret = select(max_fd, &rfds, NULL, NULL, &mytime);
if(ret < 0)
{
perror("select");
exit(-1);
}
for(int i = 0; i < max_fd; i++)
{
if(FD_ISSET(i, &rfds))
{
if(i == sockfd)
{
connfd = accept();
FD_SET(connfd, &rfds);
}
else
{
ret = read();
if(ret == 0)
{
FD_CLR(i, &rfds)
close(i);
}
}
}
}
}
注意:每一次监测之前需要还原初始表,因为在监测成功之后,初始表会发生变化
&spm=1001.2101.3001.5002&articleId=145556908&d=1&t=3&u=1e046326815c42a29092c9dfbeefcf68)
1134

被折叠的 条评论
为什么被折叠?



