Linux中的文件IO和虚拟地址空间模型 [Linux高并发服务器开发]

目录

一、标准C库的 IO 函数

二、标准C库IO 和 Linux系统IO的关系

三、虚拟地址空间

四、文件描述符

五、Linux系统IO函数

六、stat结构体

七、st_mode变量

八、Linux系统函数

1.文件属性操作函数

2.目录操作函数

3.目录遍历函数

4.dup、 dup2函数

5.fcntl函数 


一、标准C库的 IO 函数

标准C库函数写的代码,可以移植到其他操作系统。 但是基于操作系统的IO函数,需要依赖运行的操作系统。

二、标准C库IO 和 Linux系统IO的关系

 用户程序 通过调用 C的标准库中 ,读函数,写函数。 函数底层会调用操作系统的API,对磁盘文件进行读写操作。

三、虚拟地址空间

程序运行起来是一个进程,系统给程序创建了进程空间,设想成 虚拟地址空间。创建一个虚拟空间实际上并不是创建空间,而是创建映射函数所需要的相应的数据结构。为了解决程序加载内存的问题,用来解释程序内存的模型。  虚拟地址空间模型如下图

 虚拟地址空间是由CPU来决定的,32位的计算机,理想的分配的虚拟地址空间大小是2^32,大约是4G。64位的计算机,分配的虚拟地址空间大小是2^48。 4G是理想的内存空间。 实际占用 物理内存,不会占用4G,是由CPU来管理。虚拟地址空间 会被CPU的逻辑单元 MMU映射到 内存物理单元。

内存空间的分布如上图, 内存分为 用户区内核区

用户区的空间包括:

受保护的地址(0~4k).txt区代码段.data区域 .bss区域共享库栈空间命令行参数、 环境变量

受保护的地址:

NULL,nullptr都是在该地址空间。

.txt区代码段:

代码段,通常用于存放程序执行代码(即CPU执行的机器指令)。一般C语言执行语句都编译成机器代码保存在代码段。通常代码段是可共享的,因此频繁执行的程序只需要在内存中拥有一份拷贝即可。代码段通常属于只读,以防止其他程序意外地修改其指令

.data区域:

已初始化的全局变量 和 静态局部变量。

.bss区域:

未初始化的全局变量 和 静态局部变量。

.data区和.bss区 称为全局数据区。

堆空间:

从低地址往 高地址存储。new,malloc创建的数据存放在堆中。

共享库:

是 动态链接库的文件。如C标准库函数(fread、fwrite、fopen等)和Linux系统I/O函数,它们都是动态库函数,其中C标准库函数都被封装在了/lib/libc.so库文件中,都是二进制文件。这些动态库函数都是与位置无关的代码,即每次被加载进入内存映射区时的位置都是不一样的,因此使用的是其本身的逻辑地址,经过变换成线性地址(虚拟地址),然后再映射到内存。而静态库不一样,由于静态库被链接到可执行文件中,因此其位于代码段,每次在地址空间中的位置都是固定的。
 

栈空间:

从高地址往低地址存储。像局部变量,函数栈等都是存在该空间。

命令行参数:

执行程序,输入的命令行参数,存放在该内存空间中。

环境变量:

Linux中,输入env 命令,就可以看到设置的环境变量,这些环境变量,存放在该内存空间中。

内核区:

用户没有内核区操作权限。如果想操作内核数据,只能通过系统API调用。进程控制块 PCB存放于内核中进行管理。

四、文件描述符

        文件占用磁盘空间,打开了文件,是怎么找到文件,然后进行读写的呢? 因为有文件描述符,通过文件描述符,来查找相应的文件。

        文件描述符是在进程的内核区,在进程控制块PCB中。每个进程都会有一个默认的文件描述符表,这个表中存储文件描述符的数组,最大是1024,因为一个进程能打开的文件,最多是1024个。

        STDIN_FILENO 标准输入,STDOUT_FILENO标准输出,STDERR_FILENO标准错误 ,都是默认打开的状态。对应当前绑定的默认终端,因为输入,输出和错误 ,都会通过当前终端来操作或显示。

一个文件可以被打开多次,文件描述符是不同的。

Linux 中的 文件描述符的数据结构

        其中 _fileno 就是 文件描述符的序号,它来自于操作系统。

struct _IO_FILE {
  int _flags;		/* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;	/* Current read pointer */
  char* _IO_read_end;	/* End of get area. */
  char* _IO_read_base;	/* Start of putback+get area. */
  char* _IO_write_base;	/* Start of put area. */
  char* _IO_write_ptr;	/* Current put pointer. */
  char* _IO_write_end;	/* End of put area. */
  char* _IO_buf_base;	/* Start of reserve area. */
  char* _IO_buf_end;	/* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

五、Linux系统IO函数

int  open(const char* pathname, int  flags);

int  open(const char* pathname, int flags, mode_t  mode);

int  close(int fd);

ssize_t  read(int fd, void* buf, size_t  count);

ssize_t  write(int fd, const void* buf,size_t count);

off_t  lseek(int fd,off_t offset, int whence);

int  stat(const char*  pathname, struct stat* statbuf);

int  lstat(const char* pathname, struct stat* statbuf);

六、stat结构体

struct stat {
dev_t st_dev; // 文件的设备编号
ino_t st_ino; // 节点
mode_t st_mode; // 文件的类型和存取的权限
nlink_t st_nlink; // 连到该文件的硬连接数目
uid_t st_uid; // 用户ID
gid_t st_gid; // 组ID
dev_t st_rdev; // 设备文件的设备编号
off_t st_size; // 文件字节数(文件大小)
blksize_t st_blksize; // 块大小
blkcnt_t st_blocks; // 块数
time_t st_atime; // 最后一次访问时间
time_t st_mtime; // 最后一次修改时间
time_t st_ctime; // 最后一次改变时间(指属性)
};

七、st_mode变量

八、Linux系统函数

系统函数的功能,可以通过命令  man 2 function_name ,查看函数的信息。

1.文件属性操作函数

        int  access(const char*  pathname, int mode);

        int  chmod(const char* filename, int mode);

        int  chown(const char* path, uid_t owner, gid_t  group);

        int  truncate(const char* path, off_t  length);

2.目录操作函数

        int rename(const char* oldpath, const char*  newpath);

        int chdir(const char* path);

        char* getcwd(char* buf, size_t  size);

        int  mkdir(const char* pathname, mode_t  mode);

        int rmdir(const char* pathname);

3.目录遍历函数

        DIR* opendir(const char*  name);

        struct dirent* readdir(DIR*  dirp);

        int  closedir(DIR* dirp);

struct dirent
{
// 此目录进入点的inode
ino_t d_ino;
// 目录文件开头至此目录进入点的位移
off_t d_off;
// d_name 的长度, 不包含NULL字符
unsigned short int d_reclen;
// d_name 所指的文件类型
unsigned char d_type;
// 文件名
char d_name[256];
};

4.dup、 dup2函数

        int   dup(int  oldfd);/*复制文件描述符*/

        int  dup2(int oldfd, int  newfd);/*重定向文件描述符*/

5.fcntl函数 

        复制文件描述符,设置/获取文件的状态标志

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值