首页 > 其他分享 >关于文件IO缓冲区的思考

关于文件IO缓冲区的思考

时间:2023-03-10 15:22:32浏览次数:44  
标签:IO read write readbuf 思考 缓冲区 include 读取

关于文件IO缓冲区的思考

问题的提出:

关于我在实现socket的时候,有一个打印的问题一直在困扰我:
我的程序具体的实现功能是:写一个客户端和服务器,客户端写入数据,服务器打印出来,并返回给服务器,其中客户端中的输入是用select管理的
客户端发送数据的程序是这样的:
img
从键盘接受到东西以后写回套接字
服务器中接收数据的程序是这样的:
img
这里判断没有问题以后,将接收的信息打印出来
当程序运行起来以后,服务器端的输出有了问题:
客户端:img
服务器端:
img
途中标红的部分,为什么我多输出了这个字符串???

解决

检查问题后,发现,我只要将read函数中的读取数据设置成大于等于write的数据,就避免这种问题,我对此很疑惑,于是写了测试程序去测试关于read和write:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <strings.h>


int main()
{
        int fd1 = open("./1.txt", O_RDWR);
        char readbuf[BUFSIZ];
        char writebuf[BUFSIZ] = {"this is a buff test"};
        int ret = write(fd1,writebuf,sizeof(writebuf));
        if (ret < 0) perror("write");
        int fd2 = open("./1.txt", O_RDWR);
        while (1) 
        {
        ret = read(fd2,readbuf,sizeof(readbuf) - 1);
        //ret = read(fd2,readbuf,sizeof(readbuf));
        if (ret < 0) perror("read");
        if (ret > 0){
        //printf("%d\n",sizeof(BUFSIZ));
        printf("%d ",ret);
        printf("%s\n",readbuf);
        sleep(1);
        bzero(readbuf,BUFSIZ);
        }
        }
        close(fd1);
        close(fd2);

}

我这里在writebuf中并没有加换行符,也就是说,read在文件中读取数据的时候,并不会因为换行符而清空接受区,而是一直在读取,我将read的数据大小设置小于write的大小,程序运行结果如下:
img
程序并没有一直打印 我写的数据串,我们用gdb看看程序里面发生了什么:
img
img
在这我第一次读取完了以后,并没有什么异常,但有趣的是,第二次读取的字符串里面出现了"\0",才读取了文件的结束符,后续我们再读取的时候,buff里面就储存了"\0"也就是说其实在我们的输出中,buff并不是没有读到数据,而是读到了,但是它的前面有个换行符,并没有输出出来,但是我们此时read确确实实是读到了数据,也就不存在read出现perror。

总结

经过以上分析,我们可以发现,read再读取了小于缓冲区的数据时,第二次读取的时候就会没有读取的数据读取进去。
我试着理解了一下内核缓冲机制:
read&write,read把数据从内核缓冲区复制到进程缓冲区,write把数据从进程缓冲区复制到内核缓冲区,它们不等价于数据在内核缓冲区和磁盘之间的交换。
那就是说我们write写入的时BUFSIZ的数据到内核的缓冲区,read的时候读取了BUFSIZ - 1的数据,还有数据留在缓冲区中,在第二次的时候,虽然读到了,但是因为有结束符的存在,并没有让我们达到理想的效果。
ps:困扰的问题找到了答案,如果有什么不对的地方,欢迎批评指正。

标签:IO,read,write,readbuf,思考,缓冲区,include,读取
From: https://www.cnblogs.com/zhaowenrui-life/p/17203464.html

相关文章

  • Appium - iOS 定位
    iOSPredicateString定位表达式结构:属性+运算符+值#==运算符:#属性label的值与字符串"SYSTEM(TEXT)"相等label=="SYSTEM(TEXT)"#AND运算符#同时......
  • Vue在js中的使用思考,非脚手架
    varvm=newVue({el:".container",//挂载点data:{},//数据决定了页面的样子|数据的响应式=>数据变了界面跟着变computed:{},//计算属性,惰性求值的......
  • Visual Studio 编译静态库过程
    一、问题引入在写程序过程中,一般都是直接写xx.h和xx.c文件。基本上依靠这两个文件就可以完成一个简单的小项目,但是一旦构建一个大项目就会产生很多文件。这时一部分基......
  • Android Studio打包jar
    这里打包的module是不含资源文件的librarybuild.gradle添加配置taskmakeJar(type:Copy){//删除存在的delete'build/libs/mylib.jar'//......
  • mongdb.driver UpdateOptions参数解析
    在.NETMongoDB.Driver中,UpdateOptions类是MongoDB集合中更新操作的参数选项类。该类包含以下常用属性:IsUpsert:是否执行upsert操作。如果设置为true,表示文档不存......
  • @Transactional事务失效情形
    #private修饰的方式,spring无法生成动态代理#没有被spring管理。类不会被加载bean,自然事务失效。#数据库本身不支持MySQL的Myisam#事务传播行为为非事务方式PROP......
  • uniapp iOS上架流程
    上架基本需求资料 1、苹果开发者账号注册好的苹果开发者账号,个人的就可以了。缴纳年费99美刀后登录到苹果开发者后台即刻看到如下内容  简单描述一下......
  • androidstudio去掉更新提示
    Ctrl+shift+s打开设置......
  • LayoutAnimationController,补间动画,属性动画,值动画,自定义动画,帧动画
    最好的代码永远是自己写出来的布局<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools......
  • VUE-select-option 获取 label value 值
    1.绑定的value值中多赋值一个参数:value="{value:item.value,label:item.label}"2.添加@change事件进行获取值<template><el-selectv-model="value"placehol......