非阻塞IO

2023-10-13 11:36:46 浏览数 (1)

本文分享的是非阻塞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;
}

0 人点赞