readkeyboard方法_Linux笔记(12)| 几种并发式IO的实现方法

1f3ccdf5a8c1c22953250d809feac503.png

今天分享的是几种实现并发式IO的方法。什么是并发式IO呢?可以简单理解为比如要同时读取几个文件的数据,但是这些文件什么时候可以读取是不确定的,要实现当某个文件可以读取的时候就立马去读取,这就是并发式。首先提出一个问题:如果我们需要读取键盘和鼠标的信息,当键盘有按下的时候把按下的内容读取出来并且打印到屏幕上,当鼠标有动静的时候也把鼠标的设备文件读取出来,该怎么实现呢?首先想到的就是在主函数里写个while(1)挨个去读就行了,伪代码如下:
//伪代码while(1){  read(keyboard);  printf("keyboard...");  read(mouse);  printf("mouse...");}
这样的程序确实可以读取键盘和鼠标的内容并且打印出来,但是必须老老实实按照代码里的,先读键盘,再读鼠标这样往复,如果用户想要先读鼠标,再读键盘,抱歉,它会卡在前面这个read这里,因为read函数是阻塞式的,没有读到东西它就一直卡在那里。这显然不是我们希望的,我们希望像按键盘就按键盘,想动鼠标就动鼠标,并且它都能打印出来。于是,有了以下几种方法来解决这个问题。一、以非阻塞的方式来打开文件在使用open函数的时候,加上O_NONBLOCK属性,变为非阻塞,而标准输入一开始就打开了,对应文件描述符为0,所以不能用上面的方法,应该用fcntl函数来添加。变为非阻塞式的好处就是当read没有读到什么东西的时候会立马返回,不会卡在那里。代码如下:
#include #include #include #include #include #include #define pathname  "/dev/input/mice"int main(){    int fd;    int ret;    char buf[100]={0};    fd=open(pathname,O_RDWR | O_NONBLOCK);    if(fd<0)    {        perror("open failed");        return 0;    }      flag = fcntl(0, F_GETFL);    // 先获取原来的flag  flag |= O_NONBLOCK;        // 添加非阻塞属性  fcntl(0, F_SETFL, flag);    // 更新flag    while(1)    {        memset(buf,0,sizeof(buf));       ret= read(fd,buf,50);          //读鼠标    //    if(ret<0)    //    {    //        printf("read mouse ret=%d\n",ret);    //        perror("read mouse failed");    //      //  return 0;    //    }        if(ret>0)       {           printf("读出的鼠标内容是:[%s]\n",buf);       }        memset(buf,0,sizeof(buf));       ret= read(0,buf,5);          //读键盘    //    if(ret<0)    //    {    //        perror("read keyboard failed");    //        printf("read keyboard ret=%d\n",ret);    //     //   return 0;    //    }        if(ret>0)       {           printf("读出的键盘内容是:[%s]\n",buf);       }    }    return 0;}
上面的代码其实就实现了不管是按下键盘,还是点击鼠标,都能及时反应,打印出数据。但是还有更好的方法,使用系统里带的select函数或者是poll函数来监听IO的状况。二、使用select函数或者poll函数select函数和poll函数功能上差不多,是Unix两个不同的派系衍生出来的函数,后来linux把它们都吸收了。select函数在上一节使用到了,可以回顾一下:Linux笔记(11)| 网络编程之自己动手写一个服务器和客户端select函数首先把把要监听的文件描述符fd添加到一个集合里面,然后调用select函数去监听,通过返回值可以判断监听的fd的状态,比如已经可写了、或者是可读了。代码如下:
#include #include #include #include #include #include #include #include #define pathname  "/dev/input/mice"int main(void){    int ret;    int fd;    char buf[200];     struct timeval tv;      tv.tv_sec = 5;    tv.tv_usec = 0;   fd_set   myset;    fd=open(pathname,O_RDONLY);        if(fd<0)    {        perror("open mice failed");        return 0;    }   while(1)    {        FD_ZERO(&myset);        FD_SET(0, &myset);        FD_SET(fd, &myset);        ret=select(fd+1,&myset,NULL,NULL,NULL);        if(ret<0)        {            perror("select");            return 0;        }        else if(ret==0)        {            printf("time out\n");            sleep(2);        }        else        {            if( FD_ISSET(fd,&myset))            {                memset(buf,0,sizeof(buf));                read(fd,buf,5);                printf("读鼠标:[%s]\n",buf);            }           if(FD_ISSET(0,&myset))            {                memset(buf,0,sizeof(buf));                read(0,buf,5);                printf("读键盘:[%s]\n",buf);            }        }   }        return 0;}
poll函数实现的功能差不多,只是用法上有些不一样,这里直接把代码贴上:
#include #include #include #include #include #include #include #define pathname  "/dev/input/mice"int main(void){    int fd;    int ret;    char buf[100];    struct pollfd   mypoll[2]={0};    fd=open(pathname,O_RDONLY);    if(fd<0)    {        perror("open failed");        return 0;    }      while(1)    {         mypoll[0].fd=0;         mypoll[0]. events=POLLIN;         mypoll[1].fd=fd;         mypoll[1]. events=POLLIN;        ret=poll(mypoll,fd+1,10000);        if(ret<0)        {            perror("poll");            return 0;        }        else if(ret==0)        {            printf("time out\n");        }        else        {                // printf("mypoll.revents=%d\n",mypoll.revents);                // printf("mypoll.events=%d\n",mypoll.events);                if(mypoll[0].revents==mypoll[0].events)                {                    memset(buf,0,sizeof(buf));                    ret=read(0,buf,10);                    if(ret<0)                    {                        perror("read keyboard failed ");                        return 0;                    }                    printf("read keyboard:[%s]",buf);                }              if(mypoll[1].revents==mypoll[1].events)                {                    memset(buf,0,sizeof(buf));                    ret=read(fd,buf,2);                                      if(ret<0)                    {                        perror("read mouse failed ");                        return 0;                    }                    printf("read mouse:[%s]\n",buf);   //这里没加换行就不会及时打印                }                            }    }    return 0;}
三、使用异步IO第三种方法就是使用异步IO,这种方法类似于中断,就是在主函数里来处理鼠标(或者键盘也一样),然后注册一个异步IO事件,当有键盘按下的时候,产生一个异步IO信号,这个信号就会触发一个注册号的函数来处理它。代码如下:
#include #include #include #include #include #include #include #include typedef void (*sighandler_t)(int);#define pathname  "/dev/input/mice"void handler(int sig);char buf[200]; int fd;int main(void){       int flag;    int ret;        fd=open(pathname,O_RDONLY);    if(fd<0)    {        perror("open failed");        return 0;    }    // 把鼠标的文件描述符设置为可以接受异步IO    flag=fcntl(fd,F_GETFL);    flag|=O_ASYNC;    fcntl(fd,F_SETFL,flag);    // 把异步IO事件的接收进程设置为当前进程    fcntl(fd,F_SETOWN,getpid());    // 注册当前进程的SIGIO信号捕获函数     signal(SIGIO,handler);    while(1)    {        memset(buf,0,sizeof(buf));        ret=read(0,buf,10);        // if(ret<0)        // {        //     perror("read failed");        //     return 0;        // }        if(ret>0)       printf("read keyboard :[%s]\n",buf);        //sleep(2);    }    return 0;}void handler(int sig){    int ret;        if(sig!=SIGIO)        return;    memset(buf,0,sizeof(buf));    ret=read(fd,buf,5);    if(ret<0)    {        perror("read failed");        return ;    }    printf("read mouse :[%s]\n",buf);}
以上是今天分享的几种方法,实际上还可以用多进程或者多线程的方法,这在上一节里也有涉及,这里就不多说了。
猜你喜欢:Linux笔记(11)| 网络编程之自己动手写一个服务器和客户端基于红外传输的多点温度采集系统教你如何用蜂鸣器演奏乐谱

def416c76b046349bfb57623bfc26618.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/270635.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络知识:IP地址的概念以及IPV4和IPV6的区别

小伙伴们看到上面的机房了吗&#xff1f;成千上万台服务器他们都少不了一个小小的IP地址&#xff0c;每台服务器都配置了一个或多个IP。今天电脑学习微信公众号小编就带大家详细了解下IP地址都是什么&#xff1f; IP地址&#xff08;Internet Protocol Address&#xff09;是指…

新安装Win10操作系统有必要设置的几个技巧

目录 1、控制面版、回收站、网络等图标放到桌面 2、找回Win10系统删除提示框 3、关闭电脑休眠并删除hiberfil.sys 睡眠缓存文件 3、关闭Microsoft Store自动更新 4、卸载Win10自带的软件 5、关闭自动播放功能 6、删除离线地图文件并禁止更新离线地图 新安装Win10操作系统有必要…

apk私钥_获取APK证书MD5、SHA1、SHA256等秘钥

一1.先把apk解压2.在META_INF目录下找到xxx.RSA文件3.确保安装了jdk并且正确配置了环境变量4.cmd中执行keytool -printcert -file xxxx.RSA目录image.png二1.确保安装了jdk并且正确配置了环境变量。2.cmd中执行keytool -printcert -jarfile xxx.apk运行效果如下&#xff1a;ima…

查看某个端口的进程 lsof -i:端口号

查看某个端口的进程 lsof -i:端口号

10.27 noip模拟试题

1.铺瓷砖&#xff08;tile.cpp/c/pas&#xff09;【问题描述】有一面很长很长的墙。 你需要在这面墙上贴上两行瓷砖。 你的手头有两种不同尺寸的瓷砖&#xff0c;你希望用这两种瓷砖各贴一行。瓷砖的长可以用分数表示&#xff0c;贴在第一行的每块瓷砖长度为 AB &#xff0c;贴…

Windows操作系统装机必备软件,值得收藏

❤️作者主页&#xff1a;IT技术分享社区 ❤️作者简介&#xff1a;大家好,我是IT技术分享社区的博主&#xff0c;从事C#、Java开发九年&#xff0c;对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉&#xff1a; 数据库领域优质创作者&#x1f3c6;&#x…

最详细的Mac下安装nacos教程来了

什么是 Nacos 概览 欢迎来到 Nacos 的世界&#xff01; Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集&#xff0c;帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。 Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。…

电脑软件:推荐5款实用的效率软件

目录 1、图片管理神器-Image Tuner 2、系统维护神器-Dism 3、桌面效率神器-蜂窝桌面整理 4、键鼠模拟软件-按键精灵 5、书签管理神器-Toby for Chrome 今天小编大家推荐5款实用的效率神器&#xff0c;希望对大家能有所帮助&#xff01; 1、图片管理神器-Image Tuner 1000张图片…

数据库:Redis数据库优点介绍

1、速度快 不需要等待磁盘的IO&#xff0c;在内存之间进行的数据存储和查询&#xff0c;速度非常快。当然&#xff0c;缓存的数据总量不能太大&#xff0c;因为受到物理内存空间大小的限制。 2、支持多种数据库类型 丰富的数据结构 除了string之外&#xff0c;还有list、hash、…

POJ 2323 贪心

题意&#xff1a; 思路&#xff1a; 贪 贪 贪 如果当前的c>之前的cs 那么之前的合适 一直贪下去就好了 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long int n,s,rec1,c[105…

常用软件:推荐七款装机必备的软件

目录 1.桌面日历 2.FileViewPro——万能文件查看器 3.FSCapture 4.天若OCR 5.Gif Cam 6、Sticky Notes 7、PotPlayer 1.桌面日历 工作之后事情越来越多&#xff0c;一款好用的桌面日历可以让帮你掌握全局&#xff01; 点击每个窗格 可以直接添加待办事项。 完成的事件可以划横…

Ribbon、Feign和OpenFeign的区别来了

Ribbon 随着服务注册中心的安装完成后&#xff0c;客户端的负载均衡和服务的调用又是我们关注的话题。Ribbon可以实现客户端的负载均衡&#xff0c; 负载均衡LB Load Balance&#xff08;负载均衡&#xff09;&#xff1a;简单的说就是将用户的请求平摊的分配到多个服务器上…

开发插件:分享10个非常实用IDEA插件,值得看一看!

IDEA是Java开发者必备的开发神器&#xff0c;今天小编给大家分享10个十分实用的插件&#xff0c;希望能对大家的实际开发工作提供帮助&#xff01; 1. Jump To Line 快速导航插件 IntelliJ IDEA 调试器中的许多导航操作可让您在所需位置设置断点&#xff0c;但有时您只需单击即…

【bzoj1911】 Apio2010—特别行动队

http://www.lydsy.com/JudgeOnline/problem.php?id1911 (题目链接) 题意 给出一个序列&#xff0c;将序列分成连续的几段&#xff0c;每段的价值为a*s*sb*sc&#xff0c;其中a,b,c为给定常数&#xff0c;s为这一段中所有数之和。求最大价值和。 Solution 斜率优化。 dp方程&am…

网络知识:七类网线相关知识介绍

目录 一、什么是七类网线&#xff1f; 二、7类线与超6类线的区别 三、7类线用什么水晶头&#xff1f;如何制作水晶头&#xff1f; 四、七类网线的应用场景 今天给大家介绍一下七类网线相关的知识&#xff0c;希望对大家能有所帮助&#xff01; 一、什么是七类网线&#xff1f; …

效率工具:分享7款实用的任务管理软件,值得收藏!

今天小编给大家分享10款实用的任务管理工具&#xff0c;欢迎推荐给身边的朋友&#xff0c;选择一款适合自己的利器吧。1.Microsoft To-Do 微软推出的一款效率管理神器Microsoft To-Do微软推出的有款简介并且实用的待办列表效率软件&#xff0c;实用它可以轻松规划您的每一天。无…

洛谷 2921 记忆化搜索 tarjan 基环外向树

洛谷 2921 记忆化搜索 tarjan 传送门 (https://www.luogu.org/problem/show?pid2921) 做这题的经历有点玄学&#xff0c;&#xff0c;起因是某个random题的同学突然发现了一个0提交0通过的题目&#xff0c;然后就引发了整个机房的兴趣&#xff0c;&#xff0c;然后&#xff0c…

单片机位寻址举例_单片机学习:51单片机寻址方式详解

51单片机是对所有兼容Intel 8031指令系统的单片机的统称。该系列单片机的始祖是Intel 8031单片机&#xff0c;后来随着Flash rom 技术的发展&#xff0c;8031单片机取得了长足的发展&#xff0c;成为了应用最广泛的8位单片机之一。51单片机是基础入门的一个单片机&#xff0c;并…

网络知识:LAN、WAN、WLAN相关知识介绍

今天给大家介绍一下LAN、WAN、WLAN相关知识&#xff0c;希望对大家能有所帮助&#xff01; 一、什么是lan、wan和wlan口的区别&#xff1f; 很多朋友对lan口与wan及wlan的用途了解不清楚&#xff0c;尤其是在做路由器桥接时&#xff0c;wan口与lan的连接与设置容易弄混。 1、LA…