嵌入式学习-网络-Day03

嵌入式学习-网络-Day03

1.linux下IO模型及特点

1.1阻塞式IO

1.2非阻塞式IO

设置非阻塞:

1)通过函数参数设置

2)通过fcntl函数设置文件描述符属性

1.3信号驱动IO(异步IO)

1.4IO多路复用(重点)

IO多路复用场景假设

IO多路复用机制

实现IO多路复用的方式

select实现

练习1: 同时检测(监听)键盘鼠标事件。---->当键盘敲字打印键盘的字,当鼠标动的时候打印鼠标文件里的内容。

练习2:TCP实现同时链接多个客户端

练习3:在实现练习2的基础上,再检测所有用于通信的acceptfd实现并发通信。

1.linux下IO模型及特点

阻塞式IO、非阻塞式IO、异步通信IO、IO多路复用

1.1阻塞式IO

特点:最简单、最常用,效率低

阻塞I/O 模式是最普遍使用的I/O 模式,大部分程序使用的都是阻塞模式的I/O 。
缺省情况下(及系统默认状态),套接字建立后所处于的模式就是阻塞I/O 模式。
学习的读写函数在调用过程中会发生阻塞。相关函数如下:
•读操作中的read、recv、recvfrom
 读阻塞--》需要读缓冲区中有数据可读,读阻塞解除
•写操作中的write、send
写阻塞--》阻塞情况比较少,主要发生在写入的缓冲区的大小小于要写入的数据量的情况下,写操作不进行任何拷贝工作,将发生阻塞,一旦缓冲区有足够的空间,内核将唤醒进程,将数据从用户缓冲区拷贝到相应的发送数据缓冲区。 
注意:sendto没有写阻塞

1.2非阻塞式IO

特点:可以处理多路IO;需要轮询,浪费CPU资源

设置非阻塞:

1)通过函数参数设置

Recv函数最后一个参数写为0,为阻塞,写为MSG_DONTWAIT:表示非阻塞

2)通过fcntl函数设置文件描述符属性
int fcntl(int fd, int cmd, ... /* arg */ );
功能:获取/设置文件描述符属性    状态属性(O_RDONLY  O_NONBLOCK非阻塞)
参数:fd:文件描述符
      cmd:功能选择   
          状态属性: 
                  F_GETFL  :获取文件描述符原来的属性
                  F_SETFL  :设置文件描述符属性
    arg:根据cmd决定是否填充值   int
返回值:
     失败:-1
     成功:F_GETFL - 返回值的文件描述符号属性的值 int
           F_SETFL   0   

标准模板:

操作顺序:先读,后改,再写

int flag;
flag = fcntl(fd,F_GETFL);
flag|=  O_NONBLOCK;
fcntl(fd,F_SETFL,flag);

设置标准输入为非阻塞:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>int main(int argc, const char *argv[])
{
    int flag;
    flag=fcntl(0,F_GETFL);//获取文件描述符原属性
    flag |= O_NONBLOCK;//添加非阻塞属性
     // flag &= ~O_NONBLOCK;//取消非阻塞属性
    fcntl(0,F_SETFL,flag);//将新属性设置回去        char buf[32]={};
    while(1)
    {
        fgets(buf,sizeof(buf),stdin);
        printf("buf:%s\n",buf);
    }
    return 0;
}          

1.3信号驱动IO(异步IO)

特点:异步通知模式,需要底层驱动的支持

//将APP进程号告诉驱动程序
fcntl(fd, F_SETOWN, getpid());//使能异步通知
int flag;
flag = fcntl(fd,F_GETFL);
flag|= O_ASYNC ;
fcntl(fd,F_SETFL,flag);signal(SIGIO,handler)

用非阻塞方式监听鼠标的数据(操作鼠标需要加sudo权限)

查看自己使用的鼠标文件:sudo cat /dev/input/mouse0

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
int fd;
void handler(int num) // 信号处理
{
    char buf[128]={};
    int ret = read(fd,buf,sizeof(buf)-1);
    buf[ret]='\0';
    printf("buf:%s\n",buf);}
int main(int argc, char const *argv[])
{
    // 打开文件
    fd = open("/dev/input/mouse0", O_RDONLY);
    if (fd < 0)
    {
        perror("open err");
        return -1;
    }
    // 将进程号告诉驱动
    fcntl(fd, F_SETOWN, getpid());
    // 开启异步通知
    int flag;
    flag = fcntl(fd,F_GETFL);
    flag |= O_ASYNC;
    fcntl(fd,F_SETFL,flag);
    // 收到信号,调用函数
    signal(SIGIO,handler);    while (1)
    {
        printf("welcome to hqyj\n");
        sleep(1);
    }
    return 0;
}

前三种使用场景假设总结:

假设妈妈有一个孩子,孩子在房间里睡觉,妈妈需要及时获知孩子是否醒了,如何做?

  1. 进到房间陪着孩子一起睡觉,孩子醒了会吵醒妈妈:不累,但是不能干别的了
  2. 时不时进房间看一下:简单,空闲时间还能干点别的,但是很累
  3. 妈妈在客厅干活,小孩醒了他会自己走出房门告诉妈妈:互不耽误

1.4IO多路复用(重点)

IO多路复用场景假设

假设妈妈有三个孩子,分别不同的房间里睡觉,需要及时获知每个孩子是否醒了,如何做?

1.不停进每个房间看一下:简单,空闲时间还能干点别的,但是很累

2.把三个房间的门都打开,在客厅睡觉,同时监听所有房间的哭声,如果被哭声吵醒,那么能准确定位某个房间,及时处理即可:既能得到休息,也能及时获知每个孩子的状态

同时检测(监听)键盘鼠标事件。---->当键盘敲字打印键盘的字,当鼠标动的时候打印鼠标文件里的内容。

注意:如果刚才设置stdin为非阻塞的话,要改回阻塞,否则无法实现效果

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<signal.h>
#include<string.h>
int main(int argc, char const *argv[])
{
    int fd_mouse=open("/dev/input/mouse0",O_RDONLY);
    if (fd_mouse<0)
    {
        perror("open err");
        return -1;
    }
    char buf[128];
    while (1){
        //1.键盘监听
        fgets(buf,sizeof(buf),stdin);
        if (buf[strlen(buf)-1]=='\n')
        {
            buf[strlen(buf)-1]='\0';
        }
        printf("key:%s\n",buf);        int ret=read(fd_mouse,buf,sizeof(buf-1));
        buf[ret]='\0';
        printf("mouse:%s\n",buf);
        memset(buf,0,sizeof(buf));}
    return 0;
}

现象:键盘不输入,晃动鼠标无反应,没有实现功能

IO多路复用机制

其基本思想是:

先构造一张有关描述符的表(最大1024),然后调用一个函数。

当这些文件描述符中的一个或多个已准备好进行I/O时函数才返回。

函数返回时告诉进程哪个描述符已就绪,可以进行I/O操作。

基本流程:
1. 先构造一张有关文件描述符的表(集合、数组); ----》创建三个房间
2.将你关心的文件描述符加入到这个表中;        -----》将孩子放入房间
3.然后调用一个函数。 select / poll         -----》在客厅躺着
4.当这些文件描述符中的一个或多个已准备好进行I/O操作的时候
该函数才返回(阻塞)。                          ------》孩子哭了
5. 判断是哪一个或哪些文件描述符产生了事件(IO操作);  ---》哪个孩子哭了
6. 做对应的逻辑处理;                        ------》哄孩子

实现IO多路复用的方式

select实现
 int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);
   功能:select用于监测是哪个或哪些文件描述符产生事件;
   参数:nfds:    监测的最大文件描述个数
        (这里是个数,使用的时候注意,与文件中最后一次打开的文件
          描述符所对应的值的关系是什么?)
    readfds:  读事件集合; //读(用的多)
     writefds: 写事件集合;  //NULL表示不关心
     exceptfds:异常事件集合;  
     timeout:超时检测 
       如果不做超时检测:传 NULL 
       如果设置了超时检测时间:&tv
  返回值:
         <0 出错
        >0 表示有事件产生;
        ==0 表示超时时间已到;
  struct timeval {
               long    tv_sec;         /* seconds */
               long    tv_usec;        /* microseconds */
           }; void FD_CLR(int fd, fd_set *set);//将fd从表中清除
 int  FD_ISSET(int fd, fd_set *set);//判断fd是否在表中
 void FD_SET(int fd, fd_set *set);//将fd添加到表中
 void FD_ZERO(fd_set *set);//清空表

练习1: 同时检测(监听)键盘鼠标事件。---->当键盘敲字打印键盘的字,当鼠标动的时候打印鼠标文件里的内容。
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char const *argv[])
{
    // 打开文件
    int fd_mouse = open("/dev/input/mouse0", O_RDONLY);
    if (fd_mouse < 0)
    {
        perror("open err");
        return -1;
    }    // 1.创建一个表
    fd_set readfds,tempfds;
    FD_ZERO(&readfds);    // 2.将关心的文件描述符加入表中
    FD_SET(0, &readfds);
    FD_SET(fd_mouse, &readfds);    int maxfd = fd_mouse;    char buf[128] = {};
    int ret;
    while (1)
    {
        tempfds = readfds;
        //3.阻塞等待事件产生
        ret = select(maxfd + 1, &tempfds, NULL, NULL, NULL);
        if (ret < 0)
        {
            perror("select err:");
            return -1;
        }
        // 判断哪个事件产生,处理事件
        if (FD_ISSET(0, &tempfds))
        {
            // 1.键盘监听
            fgets(buf, sizeof(buf), stdin);
            if (buf[strlen(buf) - 1] == '\n')
                buf[strlen(buf) - 1] = '\0';
            printf("key:%s\n", buf);
        }
        if (FD_ISSET(fd_mouse, &tempfds))
        {
            ret = read(fd_mouse, buf, sizeof(buf) - 1);
            buf[ret] = '\0';
            printf("buf:%s\n", buf);
        }
    }
    close(fd_mouse);
    return 0;
}

select实现io多路复用的特点:

  1. 一个进程最多只能监听1024个文件描述符 (千级别)FD_SETFILE
  2. select被唤醒之后需要重新轮询一遍驱动的poll函数,效率比较低(消耗CPU资源);
  3. select每次会清空表,每次都需要拷贝用户空间的表到内核空间,效率低

练习2:TCP实现同时链接多个客户端

检测键盘和sockfd

创建流式套接字

填充结构体

绑定

监听

-----------------------------(创建服务器步骤)

创建表、清空表

添加关心文件描述符 (0,sockfd)

调用select检测

如果是键盘事件?

如果是客户端连接事件? accept

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include<string.h>int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("please input %s  port\n", argv[0]);
        return -1;
    }    // 1.创建流式套接字         协议族    类型    协议
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err:");
        return -1;
    }
    // 2.填充结构体(ipv4)
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;            // 协议族ipv4
    saddr.sin_port = htons(atoi(argv[1])); // 端口号(网络字节序)
    // saddr.sin_addr.s_addr = inet_addr(argv[1]); // ip地址(网络字节序)
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");    socklen_t len = sizeof(caddr);
    // 3.绑定
    int ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
    if (ret < 0)
    {
        perror("bind err:");
        return -1;
    }    // 4.监听
    if (listen(sockfd, 5) < 0)
    {
        perror("listen err");
        return -1;
    }    // 创建表
    fd_set readfds, tempfds;
    FD_ZERO(&readfds);    // 添加关心文件描述符
    FD_SET(0, &readfds);
    FD_SET(sockfd, &readfds);    int maxfd = sockfd;    char buf[128] = {};
    while (1)
    {
        tempfds = readfds;
        // 调用select检测
        ret = select(maxfd + 1, &tempfds, NULL, NULL, NULL);
        if (ret < 0)
        {
            perror("select err:");
            return -1;
        }
        // 键盘事件
        if (FD_ISSET(0, &tempfds))
        {
            // 1.键盘监听
            fgets(buf, sizeof(buf), stdin);
            if (buf[strlen(buf) - 1] == '\n')
                buf[strlen(buf) - 1] = '\0';
            printf("key:%s\n", buf);
        }
        // 客户端连接事件
        if (FD_ISSET(sockfd, &tempfds))
        {
            int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
            printf("acceptfd = %d\n", acceptfd);
            printf("client ip :%s,port:%d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
            close(acceptfd);
        }    }
    close(sockfd);
    return 0;
}
练习3:在实现练习2的基础上,再检测所有用于通信的acceptfd实现并发通信。

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

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

相关文章

【Qt】QTableView添加下拉框过滤条件

实现通过带复选框的下拉框来为表格添加过滤条件 带复选框的下拉框 .h文件 #pragma once #include <QCheckBox> #include <QComboBox> #include <QEvent> #include <QLineEdit> #include <QListWidget>class TableComboBox : public QComboBox …

云渲染渲染100怎么使用?

下载安装步骤&#xff1a; 访问官方网站下载客户端&#xff1a; 请访问渲染100官网&#xff1a;云渲染_性价比更高的3D云渲染平台_渲染100【官网】&#xff0c;并点击“客户端下载”按钮。 安装程序&#xff1a; 下载完成后&#xff0c;双击安装文件进行安装。在安装过程中&am…

记录运维大屏监控平台的开发、springboot实现服务器性能监测分析系统

1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a;windows 7…

Cesium基础-(Entity)-(Box)

** 里边包含Vue、React框架代码详细步骤、以及代码详细解释 ** 3、Box 盒子 以下是 BoxGeometry 类的属性、方法和静态方法,以表格形式展示: 属性 属性名类型默认值描述minimumCartesian3盒子的最小 x, y, 和 z 坐标。maximumCartesian3盒子的最大 x, y, 和 z 坐标。vertex…

CRC 校验码

试题&#xff1a;若信息码字为111000110&#xff0c;生成多项式G(x)x5x3 x1&#xff0c;则计算出的CRC校验码为&#xff08; &#xff09;。 1、多项式 通过多项式和信息码来生成校验码 按照从最高次幂到最低次幂的顺序&#xff0c;将系数依次排列就可以得到二进制表达式 x5x3…

2024年下教师资格证面试报名详细流程❗

⏰ 重要时间节点&#xff1a; &#xff08;一&#xff09;下半年笔试成绩查询&#xff1a;11月8日10:00 &#xff08;二&#xff09;注册报名&#xff1a;11月8日10:00-11日18:00 &#xff08;三&#xff09;网上审核&#xff1a;11月8日10:00-11日18:00 &#xff08;四&#x…

Flume的安装配置

一、上传解压 tar -zxvf apache-flume-1.9.0-bin.tar.gz -C /usr/local/soft/#***在环境变量中增加如下命令&#xff0c;可以使用 soft 快速切换到 /usr/local/soft***alias softcd /usr/local/soft/ 二、配置环境变量 soft #重命名 mv apache-flume-1.9.0-bin/ flume-1.9.0…

React写关键字高亮的三个方案

1.js正则replaceAlldangerouslySetInnerHTML{{ __html: xxx }}危险属性 步骤最简单,但是是危险属性,不推荐使用,项目中实在没有头绪,可以使用它应急 通过useMemo计算得到新的状态值,赋值给dangerouslySetInnerHTML属性的__html 关键代码: const [state1, setState1] useSt…

基于YOLOv11的动物类别实时检测系统(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

100多种【基于YOLOv8/v10/v11的目标检测系统】目录&#xff08;pythonpyside6界面系统源码可训练的数据集也完成的训练模型&#xff09; 摘要&#xff1a; 本文提出了一种基于YOLOv11算法的动物检测系统&#xff0c;利用7101张图片&#xff08;5521张训练集&#xff0c;1580张…

OutLook for Windows(New) 滚蛋吧

电脑OS:Windows 10 问题发生原因,不小心点击了应用商店里面的全部更新,电脑上的邮件 (UWP)应用直接给升级成最新的了,点击邮件直接闪切OutLook for Windows(New) 这个软件, 应用升级本来是一件好的事情,但是在Windows应用商店里面就是一件非常差劲的事情,有的软件升级之后更难…

力扣刷题(sql)--零散知识点(1)

通过一段时间的刷题&#xff0c;感觉自己的sql能力逐渐上去&#xff0c;所以不会像前三道题一样讲那么详细了&#xff0c;这里主要会讲到一些特殊的知识点和方法。另外&#xff0c;我的建议是做完一个题有好的想法赶紧记录下来&#xff0c;不要想着最后汇总&#xff0c;不然会懒…

文献阅读记录5-Recent Progress in the Discovery and Design of AntimicrobialPeptides

文章名字是Recent Progress in the Discovery and Design of Antimicrobial Peptides Using Traditional Machine Learning and Deep Learning&#xff0c;24年发表 摘要 由于传统抗生素的滥用和多重耐药微生物的增加&#xff0c;抗菌药物耐药性已成为一个全球性的重大健康问…

MySQL创建库,设计表

要求&#xff1a; 根据以下需求完成图书管理系统数据库及表设计&#xff0c;并建库建表&#xff0c;并截图创建表 的详细信息(desc 表名),不用添加数据 1. 用户表: 字段: 姓名&#xff0c;用户名&#xff0c;密码&#xff0c;电话&#xff0c;住址&#xff0c;专业及年级 2. 图…

Maven 项目管理工具

目录 Maven简介 Maven快速上手 Maven详细介绍 Maven工作机制 Maven安装及配置 使用IDEA创建Maven Web工程 Maven简介 Maven是 Apache 开源组织奉献的一个开源项目&#xff0c;可以翻译为“专家”或“内行”。 Maven 的本质是一个项目管理工具&#xff0c;将项目开发和管…

华为大咖说丨如何通过反馈机制来不断优化大模型应用?

本文分享自时习知 作者&#xff1a;袁泉&#xff08;华为AI数据工程专家&#xff09;全文约3015字&#xff0c;阅读约需8分钟 大模型应用正式投入使用后&#xff0c;存在一个较为普遍的情况&#xff1a;在利用“大模型提升业务运营效率”的过程中&#xff0c;业务部门和IT团队…

K8S如何基于Istio重新实现微服务

K8S如何基于Istio重新实现微服务 认识 Istio前言Istio 的理念Istio 的架构数据平面控制平面服务与 Istio 的关系 Istio 实践环境准备安装 Helm安装Istio 使用 Istio 代理运行应用情感分析应用的架构使用 Istio 代理运行应用Sidecar 注入Ingress 网关网关资源VirtualService 资源…

动态规划 —— 路径问题-不同路径

1. 不同路径 题目链接&#xff1a; 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/unique-paths/description/ 2. 算法原理 1. 状态表示&#xff1a;以莫一个位置为结尾 dp[i]表示&#xff1a;以[i&#xff0c;j]位置为结尾时&#xff0…

本地Docker部署开源WAF雷池并实现异地远程登录管理界面

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

[四轴飞行器] 航模常见术语

航模常见术语 1.X模式和模式 从结构形式上四轴飞行器可分为十字模式和X模式。十字模式如下图左所示&#xff0c;X模式如下图右所示。对于姿态测量和控制来说&#xff0c;两种结构差别不大。如果考虑安装航拍摄 像机&#xff0c;为了视线不被挡住&#xff0c;通常采用X模式。 …

mysql原理、部署mysql主从+读写分离、监控mysql主从脚本

mysql&#xff1a;工作原理 从库生成两个线程&#xff0c;一个I/O线程&#xff0c;一个SQL线程&#xff1b; i/o线程去请求主库 的binlog&#xff0c;并将得到的binlog日志写到relay log&#xff08;中继日志&#xff09; 文件中&#xff1b; 主库会生成一个 log dump 线程&…