read()函数简介

Linux下串口通信详解(下)读写串口及关闭串口 上一篇博客是串口的打开及配置,博客链接http://blog.youkuaiyun.com/specialshoot/article/details/50707965 这一篇我将要把读写串口及串口关闭的操作详细介绍一下。 读串口 读串口就是接收串口数据,通过read来实现。 read函数原型: #include ssize_t read(int fd, void *buf, size_t 阅读详情
 read
函数从打开的设备或文件中读取数据。
#include <unistd.h>    
ssize_t read(int fd, void *buf, size_t count);  
返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0
参数
count
是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置。比如用fgetc读一个字节,fgetc有可能从内核中预读1024个字节到I/O缓冲区中,再返回第一个字节,这时该文件在内核中记录的读写位置是1024,而在FILE结构体中记录的读写位置是1。注意返回值类型是ssize_t,表示有符号的size_t,这样既可以返回正的字节数、0(表示到达文件末尾)也可以返回负值-1(表示出错)。
read函数返回时,返回值说明了buf中前多少个字节是刚读上来的。有些情况下,实际读到的字节数(返回值)会小于请求读的字节数count,例如:读常规文件时,在读到count个字节之前已到达文件末尾。例如,距文件末尾还有30个字节而请求读100个字节,则read返回30,下次read将返回0。

从终端设备读,通常以行为单位,读到换行符就返回了。

从网络读,根据不同的传输层协议和内核缓存机制,返回值可能小于请求的字节数,后面socket编程部分会详细讲解。


write
函数向打开的设备或文件中写数据。

#include <unistd.h>   
ssize_t write(int fd, const void *buf, size_t count);  
返回值:成功返回写入的字节数,出错返回-1并设置errno写常规文件时,write的返回值通常等于请求写的字节数
count,而向终端设备或网络写则不一定。

读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数据到达就一直阻塞在那里。同样,写常规文件是不会阻塞的,而向终端设备或网络写则不一定。

现在明确一下阻塞(Block)这个概念。当进程调用一个阻塞的系统函数时,该进程被置于睡眠(Sleep)状态,这时内核调度其它进程运行,直到该进程等待的事件发生了(比如网络上接收到数据包,或者调用sleep指定的睡眠时间到了)它才有可能继续运行。与睡眠状态相对的是运行(Running)状态,在Linux内核中,处于运行状态的进程分为两种情况:


正在被调度执行。CPU处于该进程的上下文环境中,程序计数器(eip)里保存着该进程的指令地址,通用寄存器里保存着该进程运算过程的中间结果,正在执行该进程的指令,正在读写该进程的地址空间。


就绪状态。该进程不需要等待什么事件发生,随时都可以执行,但CPU暂时还在执行另一个进程,所以该进程在一个就绪队列中等待被内核调度。系统中可能同时有多个就绪的进程,那么该调度谁执行呢?内核的调度算法是基于优先级和时间片的,而且会根据每个进程的运行情况动态调整它的优先级和时间片,让每个进程都能比较公平地得到机会执行,同时要兼顾用户体验,不能让和用户交互的进程响应太慢。


下面这个小程序从终端读数据再写回终端。


例 28.2. 阻塞读终端


#include <unistd.h>  
#include <stdlib.h>    
int main(void)  {
   char buf[10];
   int n;
   n = read(STDIN_FILENO, buf, 10);
   if (n < 0) {
    perror("read STDIN_FILENO");
    exit(1);
   }
   write(STDOUT_FILENO, buf, n);
   return 0;  }


执行结果如下:

$ ./a.out   hello(回车)  hello  
$ ./a.out   hello world(回车)  hello 
worl$ d  bash: d: command not found

第一次执行a.out的结果很正常,而第二次执行的过程有点特殊,现在分析一下:


Shell进程创建a.out进程,a.out进程开始执行,而Shell进程睡眠等待a.out进程退出。



a.out调用read时睡眠等待,直到终端设备输入了换行符才从read返回,read只读走10个字符,剩下的字符仍然保存在内核的终端设备输入缓冲区中。


a.out
进程打印并退出,这时Shell进程恢复运行,Shell继续从终端读取用户输入的命令,于是读走了终端设备输入缓冲区中剩下的字符d和换行符,把它当成一条命令解释执行,结果发现执行不了,没有d这个命令。


如果在open一个设备时指定了O_NONBLOCK标志,read/write就不会阻塞。以read为例,如果设备暂时没有数据可读就返回-1,同时置errno为EWOULDBLOCK(或者EAGAIN,这两个宏定义的值相同),表示本来应该阻塞在这里(would block,虚拟语气),事实上并没有阻塞而是直接返回错误,调用者应该试着再读一次(again)。这种行为方式称为轮询(Poll),调用者只是查询一下,而不是阻塞在这里死等,这样可以同时监视多个设备:

while(1) {
非阻塞read(设备1);
if(设备1有数据到达)
  处理数据;
非阻塞read(设备2);
if(设备2有数据到达)
  处理数据;
...
}

如果
read(设备1)
是阻塞的,那么只要设备1没有数据到达就会一直阻塞在设备1的
read
调用上,即使设备2有数据到达也不能处理,使用非阻塞I/O就可以避免设备2得不到及时处理。

非阻塞I/O有一个缺点,如果所有设备都一直没有数据到达,调用者需要反复查询做无用功,如果阻塞在那里,操作系统可以调度别的进程执行,就不会做无用功了。在使用非阻塞I/O时,通常不会在一个while循环中一直不停地查询(这称为Tight Loop),而是每延迟等待一会儿来查询一下,以免做太多无用功,在延迟等待的时候可以调度其它进程执行。

while(1) {
   非阻塞read(设备1);
   if(设备1有数据到达)    处理数据;
   非阻塞read(设备2);
   if(设备2有数据到达)    处理数据;
   ...   sleep(n);
  }

这样做的问题是,设备1有数据到达时可能不能及时处理,最长需延迟n秒才能处理,而且反复查询还是做了很多无用功。以后要学习的select(2)函数可以阻塞地同时监视多个设备,还可以设定阻塞等待的超时时间,从而圆满地解决了这个问题。

以下是一个非阻塞I/O的例子。目前我们学过的可能引起阻塞的设备只有终端,所以我们用终端来做这个实验。程序开始执行时在0、1、2文件描述符上自动打开的文件就是终端,但是没有O_NONBLOCK标志。所以就像例 28.2 “阻塞读终端”一样,读标准输入是阻塞的。我们可以重新打开一遍设备文件/dev/tty(表示当前终端),在打开时指定
O_NONBLOCK标志。


例 28.3. 非阻塞读终端


#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <string.h>  
#include <stdlib.h>    
#define MSG_TRY "try again\n"    
int main(void)  {
   char buf[10];
   int fd, n;
   fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
   if(fd<0) {
    perror("open /dev/tty");
    exit(1);
   }
  tryagain:
   n = read(fd, buf, 10);
   if (n < 0) {
    if (errno == EAGAIN) {
     sleep(1);
     write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
     goto tryagain;
    }
     perror("read /dev/tty");
    exit(1);
   }
   write(STDOUT_FILENO, buf, n);
   close(fd);
   return 0;
  }

以下是用非阻塞I/O实现等待超时的例子。既保证了超时退出的逻辑又保证了有数据到达时处理延迟较小。


例 28.4. 非阻塞读终端和等待超时


#include <unistd.h> 
#include <fcntl.h>  
#include <errno.h> 
#include <string.h> 
#include <stdlib.h>   
#define MSG_TRY "try again\n"  
#define MSG_TIMEOUT "timeout\n"    
int main(void)  {
   char buf[10];
   int fd, n, i;
   fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
   if(fd<0) {
    perror("open /dev/tty");
    exit(1);
   } 
  for(i=0; i<5; i++) {
    n = read(fd, buf, 10);
    if(n>=0)     break;
    if(errno!=EAGAIN) {
     perror("read /dev/tty");
     exit(1); 
   } 
   sleep(1);
    write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
   } 
  if(i==5)
     write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));
  else 
    write(STDOUT_FILENO, buf, n);
   close(fd);
   return 0;
  }
C语言read函数和pread函数 与read函数不同的是,pread函数可以从指定文件描述符 fd 对应的文件中,从偏移量 offset 处开始读取数据,并将读取到的数据存储到用户空间的缓冲区 buf 中,其中参数 count 表示要读取的字节数。读取成功后,返回实际读取到的字节数;总的来说,如果需要在多线程或多进程环境下读取文件,建议使用pread函数。其中,read函数是标准I/O库提供的函数,pread函数是POSIX标准中定义的函数。读取成功后,返回实际读取到的字节数;对应的文件中读取数据,并将读取到的数据存储到用户空间的缓冲区。 阅读详情

相关推荐

readr包中read_csv()函数和write_csv()函数

R语言中readr包中的read_csv()函数和write_csv()函数基础知识学习

weixin_44231554的博客 7690

read()函数简介

read函数从打开的设备或文件中读取数据。#include ssize_t read(int fd, void *buf, size_t count); 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0

zjhkobe的专栏 4万+

Linux中的read命令详解:交互性脚本编写的利器

在Linux系统中,read命令是一个强大的工具,用于从标准输入(键盘)或其他输入流中读取用户的输入。它允许用户与脚本或命令行界面进行交互,从而使脚本更加灵活和用户友好。read命令的基本作用是等待用户输入,并将输入的内容赋值给一个或多个变量。这使得脚本能够根据用户的实时输入采取不同的行为,增加了交互性和动态性。

网络技术联盟站 2604

read()函数

read()函数

fucheng的博客 4431

【从零开始学产品经理】项目立项实战(1)——基本方案与可行性分析:基于微信小程序的记账本

主要阶段:立项-设计-开发-测试-上线-运营-总结。

Ckiyvo的博客 3210

从0到1,快速理清 | DeepSeek Harness

DeepSeek推出自研Harness开发平台,主打"一切皆插件"理念,将AI执行能力模块化为可自由组合的插件体系。带你从0到1,快速了解开发链路。

IT学习博客 673

read()和write()函数简介

read 函数从打开的设备或文件中读取数据。 #include ssize_t read(int fd, void *buf, size_t count); 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0 参数 count 是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移

wangsh217的专栏 1061

基于OSEK_TP.dll封装通用,多ECU自由切换的诊断函数库

本文介绍了基于CANoe内置OSEK_TP.dll库实现通用诊断通讯的方法。通过封装CAN_TP.cin顶层脚本,实现了ECU连接管理、数据收发和多ECU切换功能。系统采用字典结构存储ECU参数,支持从配置文件读取诊断ID等配置信息,通过TpCreateConnection建立TP层连接。文章详细说明了诊断请求发送函数Uds_DiagSendRequest的实现逻辑,以及如何利用回调函数处理收发事件。该方法无需依赖诊断数据库,通过底层封装实现了灵活高效的诊断通讯方案,适用于车载诊断领域的测试需求。

蚂蚁小兵 1565

Python之Pandas:pandas.read_csv()函数的简介、具体案例、使用方法详细攻略

​ Python之Pandas:pandas.read_csv()函数的简介、具体案例、使用方法详细攻略 目录 read_csv()函数的简介 read_csv()函数的简介 read_csv函数,不仅可以读取csv文件,同样可以直接读入txt文件(默认读取逗号间隔内容的txt文件)。 pd.read_csv('data.csv') pandas.read_csv(filepath_or_buffer, sep=',', delimiter=None, head

头部AI社区如有邀博主AI主题演讲请私信—心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,专注,谦虚,自律,反思,成长,还算比较正能量的博主,公益免费传播…内心特别想在AI界做出一些可以推进历史进程影响力的技术(兴趣使然,有点小情怀,也有点使命感呀 1万+

扩展卡尔曼滤波 (EKF, Extended Kalman Filter) 算法详解及案例分析

扩展卡尔曼滤波是一种用于估计非线性动态系统状态的递归算法。其目标是通过结合非线性系统模型和观测数据,估计系统的最优状态。

闲人编程的博客 2383

FFMPEG音视频开发: Linux下采集音频(alsa-lib库)、视频(V4L2框架)数据编码并实时推流到RTMP流媒体服务器,达到直播功能(推流)

一、环境介绍 操作系统: VM虚拟机运行的ubuntu18.04 FFMPEG版本: 4.4.2 摄像头: 罗技USB摄像头、电脑自带摄像头 声卡:电脑自带声卡 二、FFMPEG、X264的安装 参考这里:FFMPEG开发: Linux下采集摄像头数据录制成MP4视频保存到本: 地https://blog.youkuaiyun.com/xiaolong1126626497/article/d...

2989

read()函数

read()函数 用于读取文件 基本形式是:fileObject.read([size]) size表示读取的字符或字节数,为 None 或负数时读取到EOF,文件结尾处 示例: # 打开一个文件f=open('E:/test.txt','r+') str = f.read(10)print("读取的字符串是 : ", str) # 关闭打开的文件f.close() 结果输出: 读取的字符串是 : hello, ali readline()函数 一行一行读取文件,用法类似于rea..

笨狸 3885

加速访问Cloudflare的网站的解决方案

本文主要介绍了加速访问Cloudflare的网站的解决方案,希望能对大家有所帮助。通过软件计算得到最快的IP地址的效果图如下图所示,具体解决方案参考下文。 在这里插入图片描述 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 1万+

C语言中read()与write()函数总结

C语言中read()与write()函数

Armey的博客 3万+

【RH850/U2A】:HSM与APP通信(中断方式)

HSM与APP通信(中断方式)

1992

【AUTOSAR-DEM】-2.1-APP SWC设置UDS/OBD DTC检出和恢复

点击返回「《Autosar_BSW高阶配置》总目录」 案例背景(共6页精讲): DEM模块提供两种不同类型的Event: • BSW-related events:DEM_EVENT_KIND_BSW(通过C-API报告 - Dem_SetEventStatus) • SW-C-related events:DEM_EVENT_KIND_SWC(通过RTE operation - SetEventStatus) 下面我们讲讲在APP SWC中设置BusOff(总线关闭) DTC故障成立/恢复(其它

「汽车电子助手」的博客 3941

关于python3的readlines(),read()和readline()简介

关于python的readlines(),readline(),read()的介绍 1.read() 这个函数是把一个文档当成一个字符串(结尾有空字符串)返回。也就是一个文档存储在一个字符串对象中,如果文件很大,就很耗内存。 2.readlines(),是把一个文档的每一行(包含行前的空格,行末加一个\n),作为列表的一个元素,存储在一个list中。每一个行作为list的一个元素。 3.readline(),类似于readlines(),不过它每次只读取文档的一行。以后需要逐步循环(一般用whicl

digitalkee的博客 2万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

pandas中read_csv()函数的用法

read_csv()函数在pandas中用来读取文件,其语法格式为: pd.read_csv(filepath_or_buffer,header,parse_dates,index_col) 其中参数: filepath_or_buffer:字符串,或者任何对象的read()方法。这个字符串可以是URL,有效的URL方案包括http、ftp、s3和文件。可以直接写入"文件名.csv" header...

weixin_45459911的博客 1万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java FileInputStream 三种read()函数

FileInputStream流的三种read()函数对比 首先我们先创建FileIputStream流对文件进行读取 public static void main(String[] args) throws IOException { //创建File对象,保存文件夹路径iu File fin_floder = new File("C:\\test.txt"); //创建从...

kendleo的博客 1万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

open().read()函数

open 函数 你必须先用Python内置的open()函数打开一个文件,创建一个file对象,相关的方法才可以调用它进行读写。 语法: file object = open(file_name [, access_mode][, buffering]) 各个参数的细节如下: file_name:file_name变量是一个包含了你要访问的文件名称的字符串值。 access_mode...

吃不到喜洋洋的博客 1万+

Python read()函数:按字节(字符)读取文件

Python 提供了如下 3 种函数,它们都可以帮我们实现读取文件中数据的操作: read() 函数:逐个字节或者字符读取文件中的内容; readline() 函数:逐行读取文件中的内容; readlines() 函数:一次性读取文件中多行内容。 这里先讲解 read() 函数的用法,readline() 和 readlines() 函数会放到后面详细介绍。

Itmastergo的博客 9834

linux中关于文件的open()函数、read()函数和write()函数的用法

open()` 函数是一个 Linux 中非常常用的系统调用函数之一,它用于打开文件。其函数原型如下:```c```其中,`pathname` 参数表示要打开的文件路径,可以是相对路径或绝对路径;`flags` 参数定义了打开文件的方式,可以是以下一或多个标志:- `O_RDONLY`:只读方式打开;- `O_WRONLY`:只写方式打开;- `O_RDWR`:读写方式打开;- `O_CREAT`:如果文件不存在就创建它;

m0_56753665的博客 1533
上一篇: CORAB命名服务实现的简单日程管理软件
下一篇: C++堆 和 栈 空间的区别
静水若流深
博客等级 码龄14年 5粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值