Linux学习笔记之高级IO相关接口(select、poll、epoll服务器)

对于一个文件描述符,默认都是阻塞IO

非阻塞IO

fcntl函数原型

#include <unistd.h>

#include <fcntl.h>

int fcntl(int fd, int cmd, ..../* arg */ );

传入的cmd的值不同, 后⾯面追加的参数也不相同.

fcntl函数有5种功能:

  • 复制一个现有的描述符(cmd=F_DUPFD).
  • 获得/设置文件描述符标记(cmd=FGETFD 或 FSETFD).
  • 获得/设置文件状态标记(cmd=FGETFL 或 FSETFL).
  • 获得/设置异步I/O所有权(cmd=FGETOWN 或 FSETOWN).
  • 获得/设置记录锁(cmd=FGETLK,FSETLK或F_SETLKW). 

这里我们只是用第三种功能,获取/设置文件状态标记,就可以将一个文件描述符设置为非阻塞

该段代码是使用轮询方式读取标准输入

 3 #include <fcntl.h>
  4 #include <unistd.h>
  5 #include <stdio.h>
  6 
  7 void SetNonBlock(int fd)
  8 {
  9     int fl = fcntl(fd, F_GETFL);
 10     if( fl < 0 ){
 11         perror("fcntl");
 12         return;
 13     }
 14     fcntl(fd, F_SETFL, fl | O_NONBLOCK);
 15 }
 16 
 17 int main()
 18 {
 19     SetNonBlock(0); //将标准输入文件描述符设置为非阻塞
 20     while(1){  //循环读取,即轮询
 21         char buf[1024];
 22         ssize_t read_size = read(0, buf, sizeof(buf)-1);
 23         if( read_size < 0 ){
 24             perror("read");
 25             sleep(1);
 26             continue;
 27         }
 28         printf("input:%s\n", buf);
 29     }
 30     return 0;
 31 }

那么此处我们可以引出一个概念,重定向

重定向

1.dup/dup2系统调用

函数原型

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);

使用·dup将标准输出重定向到文件中

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <fcntl.h>
  4 
  5 int main()
  6 {   
  7     int fd = open("./log", O_CREAT | O_RDWR);
  8     if( fd < 0 ){
  9         perror("open");
 10         return 1;
 11     }
 12     close(1);
 13     int new_fd = dup(fd);
 14     if( new_fd != 1 ){
 15         perror("dup");
 16         return 2;
 17     }
 18     printf("new_fd: %d\n", new_fd);
 19     close(fd);
 20     
 21     for(;;){ 
 22         char buf[1024] = {0};
 23         ssize_t read_size = read(0, buf, sizeof(buf)-1);
 24         if(read_size < 0){
 25             perror("read");
 26             continue;
 27         }
 28         printf("%s", buf);
 29         fflush(stdout);
 30     }
 31     close(new_fd);
 32     return 0;
 33 }

运行结果如下:

使用dup2将标准输出重定向到文件中

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
        int fd = open("./log", O_CREAT | O_RDWR);
        if( fd < 0 ){
                perror("open");
                return 1;
        }
        close(1);

        dup2(fd, 1); //newfd为1,是fd的拷贝,所以1里面存放的是fd的内容
        for(;;){
                char buf[1024];
                ssize_t read_size = read(0, buf, sizeof(buf));
                if( read_size < 0 ){
                        perror("read");
                        break;
                }
                printf("%s", buf);
                fflush(stdout);
        }
        close(fd);
        return 0;
}

IO多路转接之select

首先我们要明确一点,无论它怎么工作,以何种方式工作,它的目的只有一个那就是等(等多个文件描述符),即它最根本的工作机制就是等待内核将数据准备好,直到被监视的多个文件描述符中的一个或者多个状态发生了改变

函数原型:

   #include <sys/select.h>
   int select(int nfds,   fd_set *readfds,   fd_set *writefds,  fd_set *exceptfds,   struct timeval *timeout);
 

参数解释:

  • 参数nfds是需要监视的最大的⽂文件描述符值+1;
  • rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合;

 关于fd_set   

其实这个结构就是一个整数数组, 更严格的说, 是一个 "位图". 使用位图中对应的位来表示要监视的文件描述 符. 提供了一组操作fd_set的接口, 来比较方便的操作位图


 void FD_CLR(int fd, fd_set *set);      // 用来清除描述词组set中相关fd 的位  

 int  FD_ISSET(int fd, fd_set *set);    // 用来测试描述词组set中相关fd 的位是否为真  

void FD_SET(int fd, fd_set *set);      // 用来设置描述词组set中相关fd的位

 void FD_ZERO(fd_set *set);           // 用来清除描述词组set的全部位


 

  • 参数timeout为结构timeval,用来设置select()的等待时间 

timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

  • 执行成功则返回文件描述词状态已改变的个数
  • 如果返回0代表在描述词状态改变前已超过timeout时间,没有返回
  • 当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds, exceptfds和timeout 的值变成不可预测。 

select使用实例1:检测标准输入

#include <stdio.h>
#include <unistd.h>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值