本文分享的是非阻塞IO,其中包括fcntl函数,然后简单代码实现轮询标志输入输出。
fcntl函数
fcntl函数是一个用于控制文件描述符的系统调用,一个文件描述符, 默认都是阻塞IO。它能够实现文件描述符的各种操作,如复制文件描述符、修改文件状态标志、获取文件状态标志等。
函数原型如下:
代码语言:javascript复制#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
参数说明:
- fd:需要操作的文件描述符;
- cmd:需要执行的操作命令;
- arg:命令所需的参数,具体取决于操作命令。
传入的cmd的值不同, 后面追加的参数也不相同,fcntl函数有5种功能:
复制一个现有的描述符(cmd=F_DUPFD):该命令会复制一个文件描述符,并返回复制后的文件描述符。 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)。 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL)::该命令可以获取和修改文件的状态标志,如O_NONBLOCK、O_APPEND等。 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)。 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)::该命令可以获取和修改文件的共享锁和独占锁。
用第三种功能, 获取/设置文件状态标记, 就可以将一个文件描述符设置为非阻塞。
在非阻塞的情况下读取数据,如果数据没有就绪,系统是以出错的形式返回(但并非出错),因此在次情况下,没有就绪和出错,使用的是相同的方式去标识。可以使用errno来区分,究竟是没有就绪还是出错。如果errno返回11,即EAGEIN==11,表示没有就绪。
使用代码简单实现非阻塞
代码语言:javascript复制#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
void SetNonBlock(int fd)
{
int f1 = fcntl(fd,F_GETFL);
if(f1 < 0)
{
perror("fcntl");
return;
}
fcntl(fd,F_SETFL,f1 | O_NONBLOCK);
}
int main()
{
SetNonBlock(0);
while(1)
{
char buffer[1024];
ssize_t s = read(0,buffer,sizeof(buffer)-1);
if(s > 0)
{
buffer[s]=0;
write(1,buffer,strlen(buffer));
printf("read success, s:%d,errno: %dn",s,errno);
}
else{
printf("read fail, s:%d,errno: %dn",s,errno);
}
sleep(1);
}
return 0;
}