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,一经查实,立即删除!

相关文章

Swift基本语法学习笔记

Swift与OC的不同点 导入框架的方式 OC使用#import <UIKit/UIKit.h>Swift使用import UIKit定义标识符的方式 Swift中定义标识符,必须指定该标识符是一个常量还是一个变量语句结束后的标志 Swift可以不用分号";"分割(只限于一行有一条语句时)OC需要分号进行分割打…

网络知识: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 帮助您更敏捷和容易地构建、交付和管理微服务平台。…

android php mysql json 查询_android php mysql json

$con mysql_connect("localhost", "db163810_f", "1e6969e2");if (!$con){die(不能建立连接: . mysql_error());}$db_selected mysql_select_db("db163810",$con);mysql_query("SET NAMES utf8");if (!$db_selected){die…

纯css改变下拉列表select框的默认样式

下列CSS就可以解决&#xff0c;原理是将浏览器默认的下拉框样式清除&#xff0c;然后应用上自己的&#xff0c;再附一张向右对齐小箭头的图片即可。 select {/*Chrome和Firefox里面的边框是不一样的&#xff0c;所以复写了一下*/border: solid 1px #000;/*很关键&#xff1a;将…

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

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

SpringCloud版本说明

SpringCloud包含了众多子项目&#xff0c;每一个子项目发布时间不一定一致&#xff0c;所以采用了伦敦地铁站为版本说明&#xff0c;而不是数字。并且从A开始是第一个发布版&#xff0c;B是第二个&#xff0c;以此类推。 SpringCloud版本SpringBoot版本Greenwich(格林威治)2.1…

JQuery中$.ajax()方法参数详解

url: 要求为String类型的参数&#xff0c;&#xff08;默认为当前页地址&#xff09;发送请求的地址。 type: 要求为String类型的参数&#xff0c;请求方式&#xff08;post或get&#xff09;默认为get。注意其他http请求方法&#xff0c;例如put和 delete也可以使用&#xff0…

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

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

bat-bat-bat (重要的事情说三遍)

去年noip前prey亲授&#xff0c;当时就觉得这是个好东西&#xff01;非常好&#xff01;然后我就没学会。接着最近被安利小红的bat&#xff01;&#xff01;&#xff01; 小红bat&#xff01;&#xff01;&#xff01; get&#xff01;&#xff01;&#xff01;谢小红&#xff…

mysql开方_MySQL数学函数的实际用法

此文章主要向大家描述的是MySQL数学函数的实际用法以及在实际操作中值得大家注意的问题&#xff0c;MySQL数学函数是MySQL函数中经常被用到的&#xff0c;所以对其有一定的了解还是有你有所帮助的。ABS (number2 ) //绝对值BIN (decimal_number ) //十进制转二进制CEILING (num…

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…

mysql调度触发器,MySQL触发器:达到某个datetime时更新

I want to create a MySQL trigger that updates a table everytime one of the datetime rows in a different table reaches a datetime lower than now.How would I accomplish this? Is that even possible?To illustrate:table_1 table_2-------- ------------------- -…

实验二简化版C语言中文理解程序文法

<程序>&#xff1a;&#xff1a;begin<语句串>end <语句串>&#xff1a;&#xff1a;<语句>{;<语句>} <语句>&#xff1a;&#xff1a;<赋值语句> <赋值语句>&#xff1a;&#xff1a;ID<表达式> <表达式>&#x…