当前位置:首页 > 嵌入式 > 嵌入式云IOT技术圈
[导读]在Linux编程中,一切皆文件,往往是对一个文件进行操作,比如说串口,和传感器打交道,一般情况下就是一来一去,一收一发,但是,如果我有多个传感器,而传感器之间又有关联,我想同时监控一个或者多个以上的文件描述符,要如何去实现这个需求呢?


▲长按图片保存可分享至朋友圈

微信公众号:嵌入式开发圈
关注可了解更多的教程。问题或建议,请公众号留言;

文章学习收集网络相关知识点进行整理,如有侵权,请联系删除。

     小编准备写一本有关嵌入式产品方面的书,投票看看大家希望我写啥?如果觉得想法可以增多,欢迎留言区讨论,写写各位圈友的支持!

提出问题

    在Linux编程中,一切皆文件,往往是对一个文件进行操作,比如说串口,和传感器打交道,一般情况下就是一来一去,一收一发,但是,如果我有多个传感器,而传感器之间又有关联,我想同时监控一个或者多个以上的文件描述符,要如何去实现这个需求呢?

解决问题

    Linux健全的API已经为我们提供了解决问题的方法,在此我们引入select()函数、poll函数。

    select()和poll()本质上来讲做的是同一件事,只是完成的方法不一样。两者都通过检验一组文件描述符来检测是否有特定的时间将在上面发生并在一定的时间内等待其发生。

[重要事项:无论select()还是poll()都不对普通文件起很大作用,它们着重用

于套接口(socket)、管道(pipe)、伪终端(pty)、终端设备(tty)和其他一些字符设备,但是这些操作都是系统相关(system-dependent)的。]

如何使用select函数?

我们先来看看select函数:

头文件包含:

1#include  /* 根据POSIX.1 - 2001 */
2/*根据早期的标准*/
3#include
4#include
5#include

函数参数解析:

 1int select(int nfds, fd_set *readset, fd_set *writeset,
2           fd_set *exceptset, struct timeval *timeout);
3
4参数解析:
5nfds :      需要检查的文件描述符个数,数值应该比是三组fd_set中最大数更大,而不是实际文件描述符的总数。
6readset:    用来检查可读性的一组文件描述符。
7writeset:   用来检查可写性的一组文件描述符。
8exceptset:  用来检查意外状态的文件描述符。(注:错误并不是意外状态)
9timeout:    NULL指针代表无限等待,否则是指向timeval结构的指针,代表最长等待时间。(如果其中tv_sec和 
10            tv_usec都等于0, 则文件描述符的状态不被影响,但函数并不挂起)

函数将返回响应操作的对应操作文件描述符的总数,且三组数据均在恰当位置被修改,只有响应操作的那一些没有修改。接着应该用FD_ISSET宏来查找返回的文件描述符组。

    select()函数的接口主要是建立在一种叫'fd_set'类型的基础上。它('fd_set')是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:

1fd_set set;
2FD_ZERO(&set);       /* 将set清零 */
3FD_SET(fd, &set);    /* 将fd加入set */
4FD_CLR(fd, &set);    /* 将fd从set中清除 */
5FD_ISSET(fd, &set);  /* 如果fd在set中则真 */

在过去,一个fd_set通常只能包含少于等于32个文件描述符,因为fd_set其实只用了一个int的比特矢量来实现,在大多数情况下,检查fd_set能包括任意值的文件描述符是系统的责任,但确定你的fd_set到底能放多少有时你应该检查/修改宏FD_SETSIZE的值。*这个值是系统相关的*,同时检查你的系统中的select()man手册。有一些系统对多于1024个文件描述符的支持有问题。

[Linux就是这样的系统!你会发现sizeof(fd_set)的结果是128(*8 =FD_SETSIZE=1024) 尽管很少你会遇到这种情况。]


测试案例
 1int isready(int fd)
2
{
3         int rc;
4         fd_set fds;
5         struct timeval tv;
6
7         FD_ZERO(&fds);
8         FD_SET(fd,&fds);
9         tv.tv_sec = tv.tv_usec = 0;
10
11         rc = select(fd+1, &fds, NULLNULL, &tv);
12         if (rc < 0)
13           return -1;
14
15         return FD_ISSET(fd,&fds) ? 1 : 0;
16}

当然如果我们把NULL指针作为fd_set传入的话,这就表示我们对这种操作的发生不感兴趣,但select() 还是会等待直到其发生或者超过等待时间。

[Linux中,timeout指的是程序在非sleep状态中度过的时间,而不是实际上过去的时间,这就会引起和非Linux平台移植上的时间不等问题。移植问题还包括在System V风格中select()在函数退出前会把timeout设为未定义的NULL状态,而在BSD中则不是这样,Linux在这点上遵从System V,因此在重复利用timeout指针问题上也应该注意。]

如何使用poll()函数?

    poll函数:

1#include 
2int poll(struct pollfd fds[], nfds_t nfds, int timeout);

    poll和select实现功能差不多,但poll效率高,以后要多用poll。poll()接受一个指向结构'struct pollfd'列表的指针,其中包括了你想测试的文件描述符和事件。事件由一个在结构中事件域的比特掩码确定。当前的结构在调用后将被填写并在事件发生后返回。在SVR4(可能更早的一些版本)中的 "poll.h"文件中包含了用于确定事件的一些宏定义。事件的等待时间精确到毫秒 (但令人困惑的是等待时间的类型却是int),当等待时间为0时,poll()函数立即返回,-1则使poll()一直挂起直到一个指定事件发生。下面是pollfd的结构。

1struct pollfd 
2{

3    int fd;        /* 文件描述符 */
4    short events;  /* 等待的事件 */
5    short revents; /* 实际发生了的事件 */
6};

select()十分相似,当返回正值时,代表满足响应事件的文件描述符的个数,如果返回0则代表在规定事件内没有事件发生。如发现返回为负则应该立即查看errno,因为这代表有错误发生。

如果没有事件发生,revents会被清空,所以你不必多此一举。

poll函数可用的测试值


    例如:

1fds[0].events = POLLIN; /*将测试条件设置成普通或优先级带数据可读*/

    然后 :

1//这样就可以监听fds里面文件描述符了,当满足特定条件就返回,并将结果保存在revents中。
2int pollresult = poll(fds,xx,xx); 
poll案例
 1#include 
2#include 
3#include 
4#include 
5#include 
6#include 
7#include 
8#include 
9
10#define MAX_BUFFER_SIZE 1024
11#define IN_FILES 3
12#define TIME_DELAY 60*5
13#define MAX(a,b) ((a>b)?(a):(b))
14
15int main(int argc ,char **argv)
16
{
17  struct pollfd fds[IN_FILES];
18  char buf[MAX_BUFFER_SIZE];
19  int i,res,real_read, maxfd;
20  fds[0].fd = 0;
21  if((fds[1].fd=open("data1",O_RDONLY|O_NONBLOCK)) < 0)
22    {
23      fprintf(stderr,"open data1 error:%s",strerror(errno));
24      return 1;
25    }
26  if((fds[2].fd=open("data2",O_RDONLY|O_NONBLOCK)) < 0)
27    {
28      fprintf(stderr,"open data2 error:%s",strerror(errno));
29      return 1;
30    }
31  for (i = 0; i < IN_FILES; i++)
32    {
33      fds[i].events = POLLIN;
34    }
35  while(fds[0].events || fds[1].events || fds[2].events)
36    {
37      if (poll(fds, IN_FILES, TIME_DELAY) <= 0)
38    {
39     printf("Poll error\n");
40     return 1;
41    }
42      for (i = 0; i< IN_FILES; i++)
43    {
44     if (fds[i].revents)
45       {
46         memset(buf, 0, MAX_BUFFER_SIZE);
47         real_read = read(fds[i].fd, buf, MAX_BUFFER_SIZE);
48         if (real_read < 0)
49        {
50         if (errno != EAGAIN)
51           {
52             return 1;
53           }
54        }
55         else if (!real_read)
56        {
57         close(fds[i].fd);
58         fds[i].events = 0;
59        }
60         else
61        {
62         if (i == 0)
63           {
64             if ((buf[0] == 'q') || (buf[0] == 'Q'))
65            {
66             return 1;
67            }
68           }
69         else
70           {
71             buf[real_read] = '\0';
72             printf("%s", buf);
73           }
74        }
75       }
76    }
77    }
78  exit(0);
79}


另外推荐相关课程:

  韦东山老师优质嵌入式学习干货推荐:包括ARM裸机开发、Linux设备驱动程序、Linux应用程序开发、Android系统学习、Linux设备树等。


在我这里购买韦东山老师的课程还可得到本人的技术支持,手把手带你学习嵌入式!

王争老师优秀数据结构算法学习课程推荐


免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭