文件系统(七)—图解进程文件操作

2023-05-16

学习文件系统,我们的目标是如何实现一个简单的文件系统?磁盘上需要什么结构?它们需要记录什么?如何访问?对于这些问题,我们就需要理解文件系统的基本工作原理,可以从以下两个方面着手

  • 文件系统的数据结构:文件系统在磁盘上使用哪些类型的结构来组织其数据和元数据?当一个进程打开一个文件时,会发生什么?在读取或写期间会访问哪些磁盘结构?
  • 访问方法:如何将进程发出的调用,如open()/write()/read()等,映射到它的结构上?在执行特定系统调用期间读取哪些结构

本章就基于以上的目的,主要学习访问过程中发生具体的细节

1 数据结构

首先,我们通过进程task_struct结构体中fs成员表示了进程可见根文件系统的根节点及当前工作目录:

task_struct{
        ...
  	struct fs_struct *fs;          /*进程目录信息*/
    struct files_struct *files;    /*进程打开文件信息*/
   ...
}

fs_struct结构体定义在/include/linux/fs_struct.h头文件:

struct fs_struct {
	int users;                     /*结构体实例用户数量*/
	spinlock_t lock;
	seqcount_t seq;
	int umask;
	int in_exec;
	struct path root, pwd;        /*进程根目录和当前工作目录*/
};

path结构体实例,结构体定义如下:

struct path {
	struct vfsmount *mnt;     /*目录项所在文件系统挂载信息,vfsmount.mnt*/
	struct dentry *dentry;    /*目录项指针*/
};
  • root成员表示进程访问内核根文件系统,通常为根文件系统的根节点,但也可以通过chroot()系统调用修改进程根目录。进程以绝对路径搜索文件时,从进程根目录开始。
  • pwd成员表示进程当前工作目录。进程以相对路径访问文件时,将会从当前工作目录开始查找。chdir()系统调用用于改变进程当前工作目录。在前面介绍的VFS初始化中,将创建内核根文件系统,并设置内核线程的根目录、当前工作目录为根文件系统根目录

在这里插入图片描述

files成员指向files_struct结构体实例,结构体定义在include/linux/fdtable.h头文件:

struct files_struct {
  /*
   * read mostly part
   */
	atomic_t count;                 /*实例引用计数*/
	bool resize_in_progress;
	wait_queue_head_t resize_wait;  /*进程等待队列*/

	struct fdtable __rcu *fdt;  /*fdtable结构体指针,初始值指向fdtab成员*/
	struct fdtable fdtab;       /*fdtable结构体成员*/
  /*
   * written part on a separate cache line in SMP
   */
	spinlock_t file_lock ____cacheline_aligned_in_smp;
  /*下一个打开文件的文件描述符,初始值为0,每次分配描述符后设置*/
	unsigned int next_fd;
  /*执行execve()系统调用时关闭文件的位图*/
	unsigned long close_on_exec_init[1];
  /*打开文件位图*/
	unsigned long open_fds_init[1];
	unsigned long full_fds_bits_init[1];
  /*打开文件file指针数组*/
	struct file __rcu * fd_array[NR_OPEN_DEFAULT];
};

files_struct结构体主要成员简介如下:

  • **open_fds_init[1]:**进程打开文件位图,与打开文件file指针数组对应,每个比特位对应数组项是否为空,1表示数组项关联了file实例
  • **fdt:**fdtable结构体指针,初始值指向fdtab成员
  • fd_array[]:file指针数组,数组项指向file实例,指针数组项索引为文件描述符,无符号整数。数组项数NR_OPEN_DEFAULT与整型数比特位数相同。
  • **fdtab:**fdtable结构体成员,用于管理文件位图,其定义如下(include/linux/fdtable.h)
struct fdtable {
	unsigned int max_fds;    /*fdtable能管理的打开文件最大数量,由位图大小决定*/
	struct file __rcu **fd;  /*指向file指针数组的指针*/
	unsigned long *close_on_exec;  /*执行execve()系统调用时关闭文件的位图*/
	unsigned long *open_fds;  /*进程打开文件位图*/
	unsigned long *full_fds_bits;
	struct rcu_head rcu;
};

文件位图就是file指针数组对应的位图,每位对应指针数组中一项,比特位位置就是数组项索引,即文件描述符

在这里插入图片描述

进程打开的文件由file结构体表示,结构体定义在include/linux/fs.h头文件:

struct file {
	union {
		struct llist_node	fu_llist;           /*单链表成员*/
		struct rcu_head 	fu_rcuhead;
	} f_u;
	struct path		f_path;                   /*文件路径信息*/
	struct inode		*f_inode;	              /*指向内核文件inode实例*/
	const struct file_operations	*f_op;    /*文件操作结构指针,通常在打开文件时设为inode->i_fop*/ 

	/*
	 * Protects f_ep_links, f_flags.
	 * Must not be taken from IRQ context.
	 */
	spinlock_t		f_lock;
	atomic_long_t		f_count;
	unsigned int 		f_flags;      /*系统调用传递的flags标记参数*/
	fmode_t			f_mode;           /*标记进程以何种模式打开文件*/
	struct mutex		f_pos_lock;
	loff_t			f_pos;            /*文件当前读写位置,相对于文件开头处的字节偏移量*/
	struct fown_struct	f_owner;
	const struct cred	*f_cred;
	struct file_ra_state	f_ra;

	u64			f_version;
#ifdef CONFIG_SECURITY
	void			*f_security;
#endif
	/* needed for tty driver, and maybe others */
	void			*private_data;      /*文件私有数据指针,例如设备文件指向驱动程序定义的数据结构*/

#ifdef CONFIG_EPOLL
	/* Used by fs/eventpoll.c to link all the hooks to this file */
	struct list_head	f_ep_links;
	struct list_head	f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
	struct address_space	*f_mapping; /*文件地址空间指针 */
} __attribute__((aligned(4)));

2 系统调用

在这里插入图片描述

透過 open(), read(), write() 等函都是以 file descriptor 为对象。而实际上这件事牵扯到 3 个面向:

  1. 每个进程自己看到的 file descriptor
  2. open file table
  3. inode:那個「檔案」真正的 inode
    在这里插入图片描述

2.1 open

open负责在内核生成与文件相对应的struct file元数据结构,并且与文件系统中该文件的struct inode进行关联,装载对应文件系统的操作回调函数,然后返回一个int fd给用户进程。后续用户对该文件的相关操作,会涉及到其相关的struct filestruct inodeinode->i_opinode->i_fopinode->i_mapping->a_ops等。

在读写文件之前,我们必须打开文件,从应用程序的角度来看,这是通过标准库的open函数来完成的,该函数返回一个文件描述符,会调用fs/open.c中的sys_open函数,代码流程如下所示:

在这里插入图片描述

  1. PathWalk找到目标文件
  2. 构造并初始化inode
  3. 构造并初始化file

在这里插入图片描述

do_filp_open()函数要完成打开文件操作最重要、最繁重的工作,函数内需要创建文件file实例,遍历文件路径中每个分量,在内核根文件系统中搜索/创建对应的dentry和inode结构体实例,当到达最末尾分量时(文件名称),将其inode实例(文件inode)与file实例建立关联。因此,do_filp_open()函数执行的主要工作可概括为从路径到节点,即由文件路径确定文件inode实例,赋予file实例

struct file *do_filp_open(int dfd, struct filename *pathname,
		const struct open_flags *op)
{
	struct nameidata nd;                      /*nameidata实例*/
	int flags = op->lookup_flags;
	struct file *filp;

	set_nameidata(&nd, dfd, pathname);        /*设置nameidata实例*/
	/* 创建file实例,依次查找各路径分量,默认设置LOOKUP_RCU标记 */
  filp = path_openat(&nd, op, flags | LOOKUP_RCU);
	if (unlikely(filp == ERR_PTR(-ECHILD)))
		filp = path_openat(&nd, op, flags);
	if (unlikely(filp == ERR_PTR(-ESTALE)))
		filp = path_openat(&nd, op, flags | LOOKUP_REVAL);
  /*释放处理符号链接中分配的save[]数组*/
	restore_nameidata();
  /*返回file实例指针*/
	return filp;
}
  • 定义了nameidata结构体实例nd,用于暂存目录项查找中间结果,并调用函数set_nameidata()设置nd实例
  • 主要工作交给path_openat(&nd, op, flags | LOOKUP_RCU)函数完成

****path_openat()函数在/fs/namei.c文件内实现,代码如下:

static struct file *path_openat(struct nameidata *nd,
			const struct open_flags *op, unsigned flags)
{
	const char *s;
	struct file *file;
	int opened = 0;
	int error;

	file = get_empty_filp();  //从slab缓存中分配file实例并初始化
	if (IS_ERR(file))
		return file;

	file->f_flags = op->open_flag; //系统调用flags参数传递的打开文件标记

	if (unlikely(file->f_flags & __O_TMPFILE)) {
		error = do_tmpfile(nd, flags, op, file, &opened);
		goto out2;
	}

	if (unlikely(file->f_flags & O_PATH)) {
		error = do_o_path(nd, flags, file);
		if (!error)
			opened |= FILE_OPENED;
		goto out2;
	}

	s = path_init(nd, flags);    //确定查找起点,s指向路径名称字符串
	if (IS_ERR(s)) {
		put_filp(file);
		return ERR_CAST(s);
	}
  /*遍历每个路径分量,创建(查找)dentry和inode实例*/
	while (!(error = link_path_walk(s, nd)) &&
		(error = do_last(nd, file, op, &opened)) > 0) {
		nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
    /* 获取最末尾路径分量符号链接路径 */
		s = trailing_symlink(nd);
		if (IS_ERR(s)) {
			error = PTR_ERR(s);
			break;
		}
	}
	terminate_walk(nd);
out2:
	if (!(opened & FILE_OPENED)) {
		BUG_ON(!error);
		put_filp(file);
	}
	if (unlikely(error)) {
		if (error == -EOPENSTALE) {
			if (flags & LOOKUP_RCU)
				error = -ECHILD;
			else
				error = -ESTALE;
		}
		file = ERR_PTR(error);
	}
	return file;  //成功返回file实例指针
}

path_openat()函数调用关系如下图所示:

在这里插入图片描述

所以do_sys_open()函数首先将系统调用flags、mode参数转换成open_flags实例,将文件路径名称参数转换成filename实例,这两个转换而得的实例将作为后面调用do_filp_open()函数的参数;调用函数get_unused_fd_flags()获取进程最小未使用文件描述符;调用**do_filp_open()**函数创建文件file实例,依次搜索/创建各路径分量(目录)对应的dentry和inode实例,将最后分量dentry、inode及file_operations实例赋予file实例;最后调用fd_install()函数建立进程file指针数组项与file实例之间的关联。
在这里插入图片描述

2.2 write

用户进程写文件内容操作的系统调用为write(),其实现与读操作非常相似,系统调用定义如下:
_vfs_write()函数内优先调用file->f_op->write()函数执行写文件操作,如果没有定义此函数则调用通用的同步写函数**new_sync_write()**完成写操作。同步写操作通常是先将数据写入文件内容缓存,然后在适当的时候同步(写入)到介质文件系统

在这里插入图片描述

2.3 read

read的读逻辑中包含预期readahead的逻辑,其可以通过与fadvise的配合达到文件预取的效果。用户进程读文件内容的read()系统调用定义如下(/fs/read_write.c):

在这里插入图片描述

3 总结

在这里插入图片描述

  • 进程1和进程2都打开同一文件,但是对应不同的file 结构体,因此可以有不同的File Status Flag和读写位置。file 结构体中比较重要的成员还有f_count,表示引用计数(Reference Count),如dup 、fork 等系统调用会导致多个文件描述符指向同一 个file 结构体,例如有fd1 和fd2 都引用同一个file 结构体,那么它的引用计数就是2,,当close(fd1) 时并不会释放file 结构体,而只是把引用计数减到1,如果再close(fd2) ,引用计数 就会减到0同时释放file 结构体,这才真的关闭了文件。
  • 每个file 结构体都有一个指向dentry结构体的指针,“dentry”是directory entry(目录项)的缩写。 我们传给open 、stat 等函数的参数的是一个路径,如/home/akaedu/a ,需要根据路径找到文件 的inode。为了减少读盘次数,内核缓存了目录的树状结构,称为dentry cache,其中每个节点是一 个dentry结构体,只要沿着路径各部分的dentry搜索即可,从根目录/找到home 目录,然后找 到akaedu目录,然后找到文件a。dentry cache只保存最近访问过的目录项,如果要找的目录项 在cache中没有,就要从磁盘读到内存中。
  • 每个dentry结构体都有一个指针指向inode 结构体。inode 结构体保存着从磁盘inode读上来的信 息。在上图的例子中,有两个dentry,分别表示/home/akaedu/a 和/home/akaedu/b ,它们都指向同 一个inode,说明这两个文件互为硬链接。inode 结构体中保存着从磁盘分区的inode读上来信息,,例如所有者、文件大小、文件类型和权限位等。每个inode 结构体都有一个指向inode_operations结 构体的指针,后者也是一组函数指针指向一些完成文件目录操作的内核函数。
  • 和file_operations 不同,inode_operations所指向的不是针对某一个文件进行操作的函数,而是影响文件和目录布局的函数,例如添加删除文件和目录、跟踪符号链接等等,属于同一文件系统的 各inode 结构体可以指向同一个inode_operations结构体。 inode 结构体有一个指向super_block结构体的指针。super_block结构体保存着从磁盘分区的超级块 读上来的信息,例如文件系统类型、块大小等。super_block结构体的s_root成员是一个指 向dentry的指针,表示这个文件系统的根目录被mount 到哪里,在上图的例子中这个分区 被mount 到/home 目录下。
  • address_space结构体,一个address_space管理了一个文件在内存中缓存的所有pages。address_space 结构其中的一个作用就是用于存储文件的 页缓存,一个inode对应一个page cache对象,一个page cache对象包含多个物理page。详细的可以参考Linux内核学习笔记(八)Page Cache与Page回写
    host:指向当前 address_space 对象所属的文件 inode 对象(每个文件都使用一个 inode 对象表示)。
    page_tree:用于存储当前文件的 页缓存。
    tree_lock:用于防止并发访问 page_tree 导致的资源竞争问题。

其对应详细的数据结构如下图所示
在这里插入图片描述

4 参考文档

文件IO系统调用内幕

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

文件系统(七)—图解进程文件操作 的相关文章

  • java:接口、lambda表达式与内部类

    接口 xff08 interface 接口用来描述类应该做什么 xff0c 而不指定他们具体应该如何做 接口不是类 xff0c 而是对符合这个接口的类的一组需求 接口定义的关键词是interface span class token key
  • 卫星系统算法课程设计 - 第二部分 qt的安装与创建项目

    上一篇文章只讲了基本的东西 xff0c 这一篇要完成qt的安装 xff0c 构建项目 xff0c 并且将上一篇的代码导入进去 某比利比例搜qt安装 xff0c 看到qt5 14 2的下载安装 xff0c 跟着做 1 创建项目 创建新项目 x
  • 无人机-材料准备

    xff08 未完成 xff09 一 使用空心杯电机 xff0c 型号8520 xff0c 1S版本 xff0c 约5G每只 二 空心杯机架 xff0c 型号QX90 xff0c 约8 5g 三 使用55MM桨 四 1S 600MA电池 五
  • CMake中链接库的顺序问题

    原文链接 xff1a https blog csdn net lifemap article details 7586363 cmake中链接库的顺序是a依赖b xff0c 那么b放在a的后面 例如进程test依赖a库 b库 a库又依赖b
  • 鸿蒙wifi Demo运行

    title 鸿蒙Wi Fi Demo运行 date 2021 1 1 22 25 10 categories harmony 本文首发于LHM s notes 欢迎关注我的博客 坑有点多 由于之前没有看过wifi的内核态代码 xff0c 所
  • 将TensorFlow训练好的模型迁移到Android APP上(TensorFlowLite)

    将TensorFlow训练好的模型迁移到Android APP上 xff08 TensorFlowLite xff09 1 写在前面 最近在做一个数字手势识别的APP xff08 关于这个项目 xff0c 我会再写一篇博客仔细介绍 xff0
  • 汉诺塔代码图文详解(递归入门)

    游戏规则 xff1a 已知条件存在A B C三根柱子 xff0c A上套有N片圆盘 如下图 目的将A上的所有圆盘移到C上约束条件每次只能移动一片圆盘 xff0c 且整个过程中只能出现小圆盘在大圆盘之上的情况 首先我们模拟 N 61 2 xf
  • STM32 最小系统电路简析

    文章目录 一 最小系统的组成1 供电电路2 外部晶振3 BOOT选择4 复位电路 二 最小系统实例1 STM32F103C8T6最小系统 三 各部分组成简析1 供电电路设计2 外部晶振原理3 BOOT设计4 复位电路设计 一 最小系统的组成
  • 带参数的宏的问题

    include 34 iostream 34 using namespace std define COMPUTE XX a a a 43 a 2 int main int a 61 2 int test1 61 COMPUTE XX 43
  • python_imbalanced-learn非平衡学习包_02_Over-sampling过采样

    python imbalanced learn非平衡学习包 01 简介 python imbalanced learn非平衡学习包 02 Over sampling过采样 后续章节待定 希望各位认可前面已更 您的认可是我的动力 Over s
  • TX2+JetPack3.2.1+opencv3.3.1+caffe+realsense2.0环境配置教程

    TX2 开箱 一共6样 xff0c 开机之后自带ubuntu16 04LTS的系统 xff0c ARMv8的处理器 xff0c 所以有些指令 xff0c 安装包必须与arm结构保持一致 开机之后 xff0c 按照指示进入图形界面 xff1a
  • 初视openwrt

    openwrt是一个微型的嵌入式操作系统 在编译的时候需要安装许多的工具和库 预置环境 xff1a sudo apt get install g 43 43 libncurses5 dev zlib1g dev bison flex unz
  • 滑动窗口详解

    前言 滑动窗口是双指针的一种特例 xff0c 可以称为左右指针 xff0c 在任意时刻 xff0c 只有一个指针运动 xff0c 而另一个保持静止 滑动窗口路一般用于解决特定的序列中符合条件的连续的子序列的问题 滑动窗口的时间复杂度是线性的
  • RT-Thread入门教程,环境配置和第一个代码

    1 前言 RT Thread这一个操作系统获得很多工程师的好评 xff0c 使用简单 xff0c 支持多 xff0c 有软件包可以下载 xff0c 甚至未来会有更多MicroPython的支持 xff0c 能够兼容主流的一些MCU xff0
  • DHT12温湿度传感器IIC,I2C接口调试心得和代码说明

    来源 xff1a http www fuhome net bbs forum php mod 61 viewthread amp tid 61 2141 DHT11那个单总线的温湿度传感器用的很多了 xff0c aosong推出了DHT12
  • 升级windows11如何在电脑上启用TPM2.0

    本文适用于无法升级到 Windows 11 xff0c 因为他们的电脑当前未启用 TPM 2 0 或其电脑能够运行 TPM 2 0 xff0c 但并未设置为运行 TPM 2 0 1 下载微软电脑健康状况检查 下载地址为 xff1a Wind
  • python调用谷歌翻译

    from GoogleFreeTrans import Translator if name 61 61 39 main 39 translator 61 Translator translator src 61 39 en 39 dest
  • C++(4) 运算符重载

    C 43 43 学习心得 xff08 1 xff09 运算符重载 from 谭浩强 C 43 43 面向对象程序设计 第一版 2014 10 6 4 1什么是运算符重载 用户根据C 43 43 提供的运算符进行重载 xff0c 赋予它们新的
  • C++学习心得(3)多态性与虚函数

    C 43 43 学习心得 xff08 3 xff09 多态性与虚函数 from 谭浩强 C 43 43 面向对象程序设计 第一版 2014 10 13 6 1 多态性的概念 在C 43 43 中 xff0c 多态性是指具有不同功能的函数可以
  • C发送http请求

    C语言发送http请求和普通的socket通讯 原理是一样的 无非就三步connect 连上服务器 send 发送数据 recv 接收数据 只不过发送的数据有特定的格式 下面的是简单发送一个http请求的例子 span class hljs

随机推荐

  • tensorflow(四十七):tensorflow模型持久化

    模型保存 span class token keyword from span tensorflow span class token keyword import span graph util graph def span class
  • git subtree使用

    在一个git项目下引用另一个项目的时 xff0c 我们可以使用 git subtree 使用 git subtree 时 xff0c 主项目下包含子项目的所有代码 使用 git subtree 主要关注以下几个功能 一个项目下如何引入另一个
  • tensorflow(四十八): 使用tensorboard可视化训练出的文本embedding

    对应 tensorflow 1 15版本 log dir span class token operator 61 span span class token string 34 logdir 34 span metadata path s
  • java中数组之间的相互赋值

    前言 本文考虑的研究对象是数组 xff0c 需要明确的是在java中 xff0c 数组是一种对象 xff0c java的所有对象的定义都是放在堆当中的 xff0c 对象变量之间的直接赋值会导致引用地址的一致 在java中声明一个数组 spa
  • tensorflow学习笔记(十):sess.run()

    session run fetch1 fetch2 关于 session run fetch1 fetch2 xff0c 请看http stackoverflow com questions 42407611 how tensorflow
  • tensorflow学习笔记(二十三):variable与get_variable

    Variable tensorflow中有两个关于variable的op xff0c tf Variable 与tf get variable 下面介绍这两个的区别 tf Variable与tf get variable tf Variab
  • pytorch 学习笔记(一)

    pytorch是一个动态的建图的工具 不像Tensorflow那样 xff0c 先建图 xff0c 然后通过feed和run重复执行建好的图 相对来说 xff0c pytorch具有更好的灵活性 编写一个深度网络需要关注的地方是 xff1a
  • pytorch学习笔记(五):保存和加载模型

    span class hljs comment 保存和加载整个模型 span torch save model object span class hljs string 39 model pkl 39 span model 61 torc
  • tensorflow:自定义op简单介绍

    本文只是简单的翻译了 https www tensorflow org extend adding an op 的简单部分 xff0c 高级部分请移步官网 可能需要新定义 c 43 43 operation 的几种情况 xff1a 现有的
  • pytorch学习笔记(十二):详解 Module 类

    Module 是 pytorch 提供的一个基类 xff0c 每次我们要 搭建 自己的神经网络的时候都要继承这个类 xff0c 继承这个类会使得我们 搭建网络的过程变得异常简单 本文主要关注 Module 类的内部是怎么样的 初始化方法中做
  • tensorflow学习笔记(四十五):sess.run(tf.global_variables_initializer()) 做了什么?

    当我们训练自己的神经网络的时候 xff0c 无一例外的就是都会加上一句 sess run tf global variables initializer xff0c 这行代码的官方解释是 初始化模型的参数 那么 xff0c 它到底做了些什么
  • 使用 spacy 进行自然语言处理(一)

    介绍 自然语言处理 NLP 是人工智能方向一个非常重要的研究领域 自然语言处理在很多智能应用中扮演着非常重要的角色 xff0c 例如 xff1a automated chat bots article summarizers multi l
  • 威联通ContainerStation部署Oracle11g

    文章目录 前言部署过程详解使用docker compose文件创建容器临时开启NAS的SSH远程访问通过SSH客户端远程连接NAS进入容器创建用户拷贝容器中的数据库相关文件至宿主机在ContainerStation中修改docker com
  • 十六进制数据与字符串的相互转换

    span class hljs keyword public span span class hljs keyword static span String span class hljs title bytesToHexString sp
  • 贪心算法详解

    前言 贪心算法是动态规划的一种特殊情况 xff0c 需要满足更为苛刻的条件 xff1a 贪心选择 算法种类时间复杂度暴力算法指数级别动态规划多项式级别贪心算法线性级别 什么是贪心选择性质呢 xff0c 简单说就是 xff1a 每一步都做出一
  • Android驱动程序开发实例精讲-0_Android系统HAL驱动开发经典案例详解(基于Android4.0)

    Android系统HAL驱动开发经典案例详解 xff08 基于Android4 0 xff09 目的 xff1a 通过学习一个LED点灯的简单功能 xff0c 掌握Linux驱动程序与HAL硬件抽象层之间的调用方法 xff0c 同时掌握JN
  • 使用putty连接到虚拟机centos被拒绝解决方法

    今天用putty去ssh本地的虚拟机中的centos系统 xff0c 发现连接被拒 xff0c 跳出了这个错误 因为是第一次用putty连接到自己电脑上的虚拟机 xff0c 碰到这个错误 xff0c 我首先想到是不是centos中的防火墙没
  • libvlc 使用mediaplayer 播放rtsp

    环境 ubuntu18 04 vlc3 0 6源码 从 github上下载的vlc 源码 xff0c 默认配置 xff0c 默认编译 xff0c 用命令 vlc rtsp 192 168 43 129 10086 stream 竟然无法播放
  • c语言下,关闭socket的两种方式

    c语言关闭socket的两种方式 一 shutdown include lt sys socket h gt int shutdown int sockfd int how how的方式有三种分别是 SHUT RD xff08 0 xff0
  • 文件系统(七)—图解进程文件操作

    学习文件系统 xff0c 我们的目标是如何实现一个简单的文件系统 xff1f 磁盘上需要什么结构 xff1f 它们需要记录什么 xff1f 如何访问 xff1f 对于这些问题 xff0c 我们就需要理解文件系统的基本工作原理 xff0c 可