【计算机网络】高级IO初步理解

news2025/2/1 16:38:26

文章目录

  • 1. 什么是IO?
    • 什么是高效 IO?
  • 2. IO的五种模型
    • 五种IO模型的概念理解
      • 同步IO与异步IO
      • 整体理解
  • 3. 阻塞IO
  • 4. 非阻塞IO
    • setnonblock函数
    • 为什么非阻塞IO会读取错误?
    • 对错误码的进一步判断
    • 检测数据没有就绪时,返回做一些其他事情
    • 完整代码
      • mytest.cc
      • makefile

1. 什么是IO?

IO:表示 输入 输出


当对方把连接建立好,但是不发数据
而我是一个线程,正在调用 read 来读,就会阻塞,一直等数据发送过来
读取条件不满足的情况下,read或recv 只会等待


无论是有数据时的拷贝 ,还是没有数据时的等待
两者的时间成本,全都算到了用户头上

在用户的角度,IO= 等+数据拷贝

什么是高效 IO?

单位时间内, 等的比重越低, IO效率越高

当IO条件满足时,称为 IO事件就绪

2. IO的五种模型

五种IO模型的概念理解

如:钓鱼假设分为两步 , 钓鱼 = 等 + 钓

在鱼竿的钩子上挂一个鱼漂,浮在水面上,用来恒定鱼竿下水的深度
当鱼漂上下摆动时,就可以知道当前有鱼上钩了


1. 张三一般喜欢专注于一件事, 所以当张三钓鱼等待时,就会一直盯着鱼漂看 是否有鱼上钩
过了一段时间,鱼漂动了,张三拉动鱼竿,将鱼钓上来了,放入桶中
继续刚才钓鱼的动作
张三在钓鱼的过程中,只盯着鱼漂看,不干其他事情


2. 李四天生好动, 所以当李四钓鱼时,就不怎么看鱼漂,会左顾右看的张望
当发现鱼咬钩后,就把鱼钓上来,放入桶中
继续刚才钓鱼的动作
李四在钓鱼的过程中,除了看鱼漂,还做其他事情


3. 王五比较特别, 当王五钓鱼时,在鱼竿的顶部放上一个铃铛,等待鱼上钩
等待过程中,王五做着自己的事情
当王五听到铃铛响了时,就拉动鱼竿,将鱼钓上来了,放入桶中
继续刚才钓鱼的动作
王五在钓鱼的过程中,不看鱼漂,只听铃铛来判断是否有鱼上钩


4. 赵六是周围的首富,开皮卡来钓鱼,皮卡上装了10根鱼竿 (首富是来体验生活的)
使用10根鱼竿一起钓鱼,赵六就从前往后 依次查看 是否有鱼漂在动


5. 田七是方圆500公里的首富 (田七比赵六有钱)
田七很忙,每天都有各种会议要开,而且田七并不是想钓鱼,而是喜欢吃鱼
所以就 让司机小王帮忙去钓鱼
当鱼桶满了后,给田七打电话,就会来人把鱼带走
小王在钓鱼时,田七也正在开会


张三和李四钓是一样的,差别在等待鱼上钩的方式不同
张三为 鱼漂不动,他不动
李四为 鱼漂不动,会立马返回去做其他事情


张三的钓鱼方式 称为 阻塞IO
(数据没有就绪,调用的read接口不会返回)


李四的钓鱼方式 称为 非阻塞IO
(检测一次若没有数据,则会立马返回,过一段时间可以再次检测)


王五在鱼还没有钓上来之前,就知道当铃铛响了,就应该拉动鱼竿
王五的钓鱼方式 称为 信号驱动IO


赵六一次管理多个鱼竿,赵六的钓鱼方式称为 多路复用或多路转接

在这几个人中,赵六的钓鱼效率比较高
因为赵六的鱼竿比较多,所以鱼上钩的概率大 即等待时间比较短
所以赵六的钓鱼效率比较高


同步IO与异步IO

前四个人都要钓鱼的过程,所以都称为 同步IO

田七没有参与钓鱼的过程,没有等 ,也没有钓,只是 发起钓鱼的过程
田七的钓鱼方式 称为 异步IO


整体理解

钓 可以看作 数据拷贝
张三 李四 等人 可以看作 进程
田七可以看作是一个进程,司机小王可以看作是操作系统
鱼竿可以看作 文件描述符
鱼 可以看作是 数据
鱼咬钩 或 鱼漂动 、铃铛响 可以看作 IO事件就绪


一个进程 在文件描述符上读取数据时,若数据没有就绪,当前进程只能挂起等待
直到有IO时间就绪,数据才可以拷贝到对应的上层

3. 阻塞IO

阻塞IO:数据没有就绪,调用的read接口不会返回


通过使用 read 函数 从键盘中读,当代码写好时,若什么也不输入,则什么也不显示 则为阻塞IO

输入 man 2 read

从一个文件描述符 中 去读count个数据 到 buf缓冲区中
若获取成功,则返回 字节数据
若获取 为0,则表示读到文件结尾
若获取为-1,则表示失败,并设置错误码


0表示标准输入流
从标准输入流中 读buffer数组大小的数据 发送到 buffer中

运行可执行程序后,一直不输入,则导致read在等待,直到有数据输入才进行数据拷贝

4. 非阻塞IO

非阻塞IO:检测一次若没有数据,则会立马返回 做其他事情,过一段时间可以再次检测


通过使用 read 函数 从键盘中读,当代码写好时,就是不输入
通过这样的方式,模拟读取条件不满足的情况下,read只会等待的情况

在上述阻塞IO的代码的基础上 进行修改


setnonblock函数

输入 man fcntl

第一个参数为 文件描述符
第二个参数 表示 你要对文件描述符干什么
获得/设置文件状态标记(cmd=F_GETFLF_SETFL)

通过设置文件状态标记,就可以将一个文件描述符 变为 非阻塞

使用 F_GETFL,将当前文件描述符的属性取出来
使用 F_SETFL,将文件描述符 状态进行设置,并加上一个 O_NONBLOCK (非阻塞) 参数

若函数返回 -1,则表示失败


创建一个函数 setnonblock,将文件描述符设置为非阻塞状态
先使用F_GETFL,获取对应文件描述符的属性
若获取失败,则返回错误原因和错误码
若获取成功,则使用 F_SETFL 将文件描述符状态设为非阻塞状态


为什么非阻塞IO会读取错误?

在主函数main中,将标准输入流改为非阻塞状态
并根据read的三种返回值,分别设置 返回提示 : 读取成功、文件结尾 和 读取错误


当将标准输入流设置为非阻塞状态后
再次运行可执行程序,直接就会读取失败
在调用read时,发现数据没有就绪 (当前读取检测速度太快,还没有输入,就报错了)

所以一旦底层数据没有就绪,就以出错的形式返回,但是不算真正的出错


但这样就没办法区分是真正出错还是 底层没有数据了
所以就通过出错码 进行进一步判断

对错误码的进一步判断

EAGAIN EWOULDBLOCK 都是系统设置的,错误码都是11
用于判断没出错,但是以出错的形式返回 的错误码
若为真,则下次继续检测即可


若IO被信号中断,则重新检测


检测数据没有就绪时,返回做一些其他事情

非阻塞IO,是可以做到 当检测数据没有就绪 时,就返回做一些其他事情


定义一个 包装器 其参数为void 返回值为void ,并将其重命名为 func_t 类型
定义一个vetcor数组 ,其类型为 func_t


设置三个任务,分别为PrintLog OperMysql CheckNet


在创建LoadTask函数,将任务分别插入到funcs数组中


在主函数main中,调用 LoadTask函数 以此加载任务


创建一个 HandlerALLTask函数,用于遍历 vector数组 ,数组元素为任务
当数据没有就绪时,就返回 处理任务


完整代码

mytest.cc

#include<iostream>
#include<unistd.h>
#include<fcntl.h>
#include<cstdio>
#include<cstring>
#include<vector>
#include<functional>
using namespace std;

//任务
void PrintLog()//打印日志
{
   cout<<"这是一个打印日志例程"<<endl;
}

void OperMysql()
{
  cout<<"这是一个操作数据库的例程"<<endl;
}

void CheckNet()
{
    cout<<"这是一个检测网络状态的例程"<<endl;
}

using func_t =function<void(void)>;
vector<func_t>  funcs;

void LoadTask()
{
    funcs.push_back(PrintLog);
    funcs.push_back( OperMysql);
    funcs.push_back(CheckNet);
}

void HandlerALLTask()
{
    //遍历vector数组
  for(auto& func:funcs)
  {
    func();
  }
}

void SetNonBlock(int fd)//将文件描述符设为非阻塞
{
   int fl=fcntl(fd,F_GETFL);//获取当前文件描述符的指定状态标志位
    if(fl<0)//获取失败
    {
          cerr<<"error string: "<<strerror(errno)<<"error code: "<<errno<<endl;
    }
    fcntl(fd,F_SETFL,fl | O_NONBLOCK);//将文件描述符状态设为非阻塞状态
}

int main()
{
    char buffer[64];
    SetNonBlock(0);//将标准输入流 改为非阻塞状态
    LoadTask();//加载任务
   while(true)
   {
    
      //0表示标准输入流
      ssize_t n=read(0,buffer,sizeof(buffer)-1);//检测条件是否就绪
      if(n>0)//读取成功
      {
        buffer[n-1]=0;    
        cout<<"echo# "<<buffer<<endl; 
      }
      else if(n==0)//读到文件结尾
      {
        cout<<"end file"<<endl;
      }
      else//读取失败 
      {
        if(errno==EAGAIN || errno ==EWOULDBLOCK)
        {
          //若为真,说明没出错,只是以出错返回
          //底层数据没有准备好,下次继续检测

          HandlerALLTask();//遍历数组 处理任务
          sleep(1);
          cout<<"data not  ready"<<endl;
          continue;
          
        }
        else if(errno == EINTR)
        {
            //IO被信号中断,需要重新检测
            continue;
        }
        else //真正的错误
        {
             cout<<"read error"<<"error string: "<<strerror(errno)<<"error code: "<<errno<<endl;
             break;
        }
      }
      sleep(1);

   }
    return 0;
}

 

makefile

mytest:mytest.cc
	g++ -o $@ $^ -std=c++11
	
.PHONY:clean
clean:
	rm -f mytest

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

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

相关文章

好奇喵 | Tor浏览器——层层剥开洋葱

前言 在之前的博客中&#xff0c;Surface Web —&#xff1e; Deep Web —&#xff1e; Dark Web&#xff0c;我们解释了表层网络、深层网络等的相关概念。 本篇博客介绍Tor浏览器&#xff0c;并且把Tor浏览器的洋葱层层剥开&#xff0c;了解其历史&#xff0c;工作原理&…

c++的发展史以及如何学习

文章目录 1. 什么是C 2. C发展史 3. C的重要性 4. 如何学习C 文章内容 1. 什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的 程序&#xff0c;需要高度的抽象和建模时&#xff0c;C语言则不合适。为了解决软…

【AI视野·今日Robot 机器人论文速览 第四十七期】Wed, 4 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Wed, 4 Oct 2023 Totally 40 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;基于神经网络的多模态触觉感知, classification, position, posture, and force of the grasped object多模态形象的解耦(f…

Pikachu靶场——远程命令执行漏洞(RCE)

文章目录 1. RCE1.1 exec "ping"1.1.1 源代码分析1.1.2 漏洞防御 1.2 exec "eval"1.2.1 源代码分析1.2.2 漏洞防御 1.3 RCE 漏洞防御 1. RCE RCE(remote command/code execute)概述&#xff1a; RCE漏洞&#xff0c;可以让攻击者直接向后台服务器远程注入…

二叉树经典例题

前言&#xff1a; 本文主要讲解了关于二叉树的简单经典的例题。 因为二叉树的特性&#xff0c;所以关于二叉树的大部分题目&#xff0c;需要利用分治的思想去递归解决问题。 分治思想&#xff1a; 把大问题化简成小问题&#xff08;根节点、左子树、右子树&#xff09;&…

【C++】STL详解(十)—— 用红黑树封装map和set

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C学习 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C】STL…

国庆中秋特辑(八)Spring Boot项目如何使用JPA

目录 一、Spring Boot 项目使用 JPA 的步骤二、Spring Boot 项目使用 JPA 注意事项三、Spring Boot 项目使用 JPA 常用语法 Spring Boot项目如何使用JPA&#xff0c;具体如下 一、Spring Boot 项目使用 JPA 的步骤 添加依赖 在项目的 pom.xml 文件中添加 Spring Boot JPA 和数…

如何使用 ChatGPT 创建强大的讲故事广告

shadow&#xff1a; 使用AI技术来辅助创作故事越来越流行&#xff0c;从事营销相关工作的人员需要不断适应和学习新的技术和工具&#xff0c;以应对行业的变化和挑战。 如何使用ChatGPT创建讲故事的广告&#xff1a; A. 确定品牌故事和信息传递B. 确定目标受众C. 开发概念D. 使…

【LeetCode热题100】--153.寻找旋转排序数组中的最小值

153.寻找旋转排序数组中的最小值 由于该排序数组经由1到n次旋转&#xff0c;所以旋转后的数组折线图为&#xff1a; 最小值处于中间&#xff0c;同时对于最后一个元素x&#xff1a;在最小值右侧的元素&#xff0c;它们的值一定严格小于x,而在最小值左侧的元素&#xff0c;它们的…

因为在此系统上禁止运行脚本

问题&#xff1a; 解决办法&#xff1a; vue项目搭建中"因为在此系统上禁止运行脚本"报错&#xff0c;解决方法 - 你的剧本 - 博客园 (cnblogs.com)

文举论金:黄金原油全面走势分析策略独家指导

市场没有绝对&#xff0c;涨跌没有定势&#xff0c;所以&#xff0c;对市场行情的涨跌平衡判断就是你的制胜法宝。欲望&#xff01;有句意大利谚语&#xff1a;让金钱成为我们忠心耿耿的仆人&#xff0c;否则&#xff0c;它就会成为一个专横跋扈的主人。空头&#xff0c;多头都…

10.2 调试事件获取DLL装载

理解了如何通过调试事件输出当前进程中寄存器信息&#xff0c;那么实现加载DLL模块也会变得很容易实现&#xff0c;加载DLL模块主要使用LOAD_DLL_DEBUG_EVENT这个通知事件&#xff0c;该事件可检测进程加载的模块信息&#xff0c;一旦有新模块被加载或装入那么则会触发一个通知…

大数据Doris(四):直接编译(CentOS/Ubuntu)准备

文章目录 直接编译(CentOS/Ubuntu)准备 一、环境准备

国庆与中秋两节合一的长假

国庆节是我国最重要的节日之一&#xff0c;而中秋节则是一个家庭团聚和感恩的时刻&#xff0c;当这两个重要的节日同时降临&#xff0c;就为人们带来了双重的欢庆。今年&#xff08;2023&#xff09;的国庆节与中秋节难得地重合在一起&#xff0c;让人们享受了长达8天的假期。这…

一文看懂功率MOSFET FCP190N60 N沟道 基础知识

什么是MOSFET的原意是&#xff1a;MOS&#xff08;Metal Oxide Semiconductor金属氧化物半导体&#xff09;&#xff0c;FET&#xff08;Field Effect Transistor场效应晶体管&#xff09;&#xff0c;即以金属层&#xff08;M&#xff09;的栅极隔着氧化层&#xff08;O&#…

实验室超声波萃取技术的原理和特点是什么?

梵英超声(fanyingsonic)实验室超声波清洗机 超声波萃取中药材的优越性源于超声波的特殊物理性质。通过压电换能器产生的快速机械振动波&#xff0c;超声波可减少目标萃取物与样品基体之间的作用力&#xff0c;从而实现固液萃取分离。 &#xff08;1&#xff09;加速介质质点运…

13个最强大的摄影测量软件【2023最新】

如果你曾经使用 Google 地球探索过外国城市或玩过《堡垒之夜》&#xff0c;就会体验到摄影测量的好处。 通过将多张航空照片以及来自 NASA 的海拔和地形信息相结合&#xff0c;Google 地球可以创建大多数主要城市的逼真 3D 视图。 视频游戏制造商 Epic Games 使用摄影测量技术…

苹果V3签名是什么?优势是什么?什么场合需要应用到?该怎么部署?

v3签名&#xff0c;或称为Apple Developer Program v3签名&#xff0c;是苹果公司在2021年6月推出的一种签名格式&#xff0c;用于对应用程序进行签名和验证。 它是取代了之前的v2签名格式&#xff0c;用于增强应用程序的安全性和完整性。 v3签名能够做到以下几点&#xff1a;…

[硬件基础]-快速了解PWM

快速了解PWM 文章目录 快速了解PWM1、什么是PWM2、PWM的频率3、PWM的占空比4、PWM信号的输出电压计算5、脉宽调制幅度6、脉冲宽度调制生成技术6.1 使用微控制器生成脉冲宽度调制6.2 使用模拟电路产生脉冲宽度调制6.3 其他产生PWM的方法 在本文中&#xff0c;将介绍脉宽调制。 脉…

QT基础入门——信号和槽机制(二)

前言&#xff1a; 在Qt中&#xff0c;有一种回调技术的替代方法&#xff1a;那就是信号和槽机制。当特定事件发生时&#xff0c;会发出一个信号。Qt的小部件中有许多预定义的信号&#xff0c;但我们可以将小部件子类化&#xff0c;向它们添加自定义的信号。槽是响应特定信号的…