Linux系统编程(2)

手动文件锁定

#include <stdio.h>
void flockfile(FILE* stream);void funlockfile(FILE* stream);//非阻塞函数
int ftrylockfile(FILE* stream);

不会锁定流的操作

#define _GNU_SOURCE
#include <stdio.h>int fgetc_unlocked(FILE* stream);
char *fgets_unlocked(char*str, int size, FILE* stream);
size_t fread_unlocked(void* buf, size_t size, size_t nr, FILE* stream);
int fputc_unlocked(int c, FILE* stream);
int fputs_unlocked(const char* str, FILE* stream);
size_t fwrite_unlocked(void * buf, size_t size, size_t nr, FILE* stream);int fflush_unlocked(FILE* stream);
int feof_unlocked(FILE* stream);
int ferror_unlocked(FILE* stream);
int fileno_unlocked(FILE* stream);
void clearerr_unlocked(FILE* stream);

标准IO最大的问题在于性能受到两次复制的影响,读取数据时,标准IO会对内核进行read()系统调用,从内核复制数据到标准IO缓冲区,如果有一个应用程序接着通过标准IO送出一个读取请求,则数据会被再复制一次,会从标准IO缓冲区复制到所提供的缓冲区中,写入请求则逆向运作,数据从提供的缓冲区被复制到标准IO缓冲区,然后通过write()系统调用从标准IO缓冲区被复制到内核。

readv()和writev()

#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec *iov, int count);
ssize_t writev(int fd, const struct iovec* iov, int count);struct iovec {void* iov_base;size_t iov_len;
};

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>int main() {struct iovec iov[3];ssize_t nr;int fd, i;char* buf[] = {"The term buccaneer comes from the word boucan.\n", "A boucan is a wooden frame used for cooking mear.\n","Buccaneer is the West Indies name for a pirate.\n"};fd = open("buccaneer.txt", O_WRONLY | O_CREAT | O_TRUNC);if (fd == -1) {perror("open");return 1;}// 填三个iovec结果for (int i = 0; i < 3; i++) {iov[i].iov_base = buf[i];iov[i].iov_len = strlen(buf[i]);}// 单词调用将他们写出nr = writev(fd, iov, 3);if (nr == -1) {perror("writev");return 1;}printf("wrote %ld bytes\n", nr);if (close(fd)) {perror("close");return 1;}return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <string.h>int main() {// 下面的长度如果变化,结果会有不同的// char foo[47], bar[50], baz[48];// char foo[47], bar[51], baz[48];char foo[47], bar[50], baz[47];struct iovec iov[3];ssize_t nr;int fd, i;fd = open("buccaneer.txt", O_RDONLY);if (fd == -1) {perror("open");return 1;}iov[0].iov_base = foo;iov[0].iov_len = sizeof(foo);iov[1].iov_base = bar;iov[1].iov_len = sizeof(bar);iov[2].iov_base = baz;iov[2].iov_len = sizeof(baz);// 单次调用读取nr = readv(fd, iov, 3);if (nr == -1) {perror("readv");return 1;}for (i = 0; i < 3; i++) {printf("%d-%ld: %s", i, strlen((char*)iov[i].iov_base), (char*)iov[i].iov_base);}if (close(fd)) {perror("close");return 1;}return 0;}

获取页大小

long page_size = sysconf(_SC_PAGESIZE);或者#include <unistd.h>
int getpagesize(void);

页面大小也被静态存储在PAGE_SIZE(定义于<asm/page.h>)中,因此获取页面大小的第三种方式为int page_size = PAGE_SIZE;

 mmap函数的用法详解及实例分析-CSDN博客

 Linux C | mmap使用实例_mmap使用示例-CSDN博客

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>int main() {int fd;void *mmap_addr;struct stat sb;fd = open("buccaneer.txt", O_RDONLY);fstat(fd, &sb);mmap_addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (mmap_addr == MAP_FAILED) {return -1;}printf("%s\n", (char*)mmap_addr);munmap(mmap_addr, sb.st_size);close(fd);return 0;
}

mmap优点

相比较于标准的read()和write()系统调用,经过mmap映射有以下优点:

1、对内存映射文件进行读取和写入操作,可避免使用read和write系统调用时所产生的无关副本,read和write会将数据复制到一个用户空间缓冲区,并从用户缓冲区复制回来。

2、除了可能的页面失误,对内存映射文件的读写操作不会产生任何系统调用或操作环境切换的开销,进行简单的内存操作即可。

3、当有多个进程将同一个对象映射至内存时,数据由这些进程共享,对类型为read-only以及shared的可写入映射而言,所共享的是他们的全部,对类型为private的可写入映射而言,所共享的是他们尚未被“写入时复制”的页面。

4、映射的查找仅涉及很少的指针操作,不需要使用lseek系统调用。

mmap缺点

1、内存映射往往是页面大小的整数倍,可能会造成内存浪费。

2、内存映射必须适合放入进程的地址空间。

3、创建和维护内存映射以及内核内部相关的数据结构是有代价的。

调整映射的大小

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/mman.h>void* mremap(void* addr, size_t old_size, size_t new_size, unsigned long flags);

 Linux所特有的mremap系统调用可以用于扩大或者缩小所指定的映射的大小。将位于[addr, addr+old_size)中的内存区间扩大或者缩小为new_size,可能会发生地址移动。

输出特定文件的iNode编号

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>int get_inode(int fd) {struct stat buf;int ret;ret = fstat(fd, &buf);if (ret < 0){perror("fstat");return -1;}return buf.st_ino;
}int main(int argc, char* argv[]) {int fd, inode;if (argc < 2) {fprintf(stderr, "usage: %s <file>\n", argv[0]);return 1;}fd = open(argv[1], O_RDONLY);if (fd < 0) {perror("open");return 1;}inode = get_inode(fd);printf("%d\n", inode);return 0;
}

获取文件的逻辑块

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>/*
*fd相关的文件,映射至logical_block物理块
*/
int get_block(int fd, int logical_block) {int ret;ret = ioctl(fd, FIBMAP, &logical_block);if (ret < 0) {perror("ioctl");return -1;}return logical_block;
}/*
* get_nr_blocks   返回与fd相关联的文件所耗用的逻辑块的数目
*/
int get_nr_blocks(int fd) {struct stat buf;int ret;ret = fstat(fd, &buf);if (ret < 0) {perror("fstat");return -1;}return buf.st_blocks;
}/*** @brief 输出(logical blocks, physical block)* */
void print_blocks(int fd) {int nr_blocks, i;nr_blocks = get_nr_blocks(fd);if (nr_blocks < 0) {fprintf(stderr, "get_nr_blocks failed!\n");return;}if (nr_blocks == 0) {printf("no allocated blocks\n");return;} else if (nr_blocks == 1) {printf("1 bllock\n\n");} else {printf("%d blocks\n\n", nr_blocks);}for (i = 0; i < nr_blocks; i++) {int phys_block;phys_block = get_block(fd, i);if (phys_block < 0) {fprintf(stderr, "get_block failed!\n");return;}if (!phys_block) {continue;}printf("(%u, %u) ", i, phys_block);}putchar('\n');}int main(int argc, char* argv[]) {int fd;if(argc < 2) {fprintf(stderr, "usage: %s<file>\n", argv[0]);return 1;}fd = open(argv[1], O_RDONLY);if (fd < 0) {perror("open");return 1;}print_blocks(fd);return 0;
}

获取进程号和父进程号

#include <sys/types.h>
#include <unistd.h>pid_t getpid(void);
pid_t getppid(void);

exec系列调用

#include <unistd.h>int execl(const char* path, const char* arg, ...);
//不定参数必须以NULL结尾
//下面执行会将/bin/vi取代当前所执行的程序int ret;
ret = execl("/bin/vi", "vi", NULL);
if (ret == -1) perror("execl");
#include <unistd.h>int execlp(const char* file, const char* arg, ...);
int execle(const char* path, const char* arg, ..., char* const envp[]);
int execv(const char* path, char* const argv[]);
int execvp(const char* file, char* const argv[]);
int execve(const char* filename, char* const argv[], char* const envp[]);

使用wait检测子进程的状态

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>int main() {int status;pid_t pid;if (!fork()) {// 子进程// return 1;abort();}pid = wait(&status);if (pid == -1) perror("wait");printf("pid=%d\n", pid);if (WIFEXITED(status)) {printf("Normal termination with exit status=%d\n", WEXITSTATUS(status));}if (WIFSIGNALED(status)) {printf("Killed by signlal=%d%s\n", WTERMSIG(status), WCOREDUMP(status) ? " (dumped core)" : "");}if (WIFSTOPPED(status)) {printf("Stopped by signal=%d\n", WSTOPSIG(status));}if (WIFCONTINUED(status)) {printf("Continued\n");}return 0;
}

等待特定进程waitpid

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>// pid_t waitpid(pid_t pid, int * status, int options)/*** @brief pid参数说明* <-1  等待其进程组ID等于此值的绝对值的任何子进程,例如传入-500, 则等待进程组ID为500的任何进程* -1   等待任何子进程,此刻的行为如同wait()* 0    等待与calling process (进行调用的进程)均属于同一个进程组的任何子进程* >0   等待其pid等于所指定值的任何子进程,例如传入500,则表示等待进程号为500的子进程* status参数的行为如同wait的参数,可以使用前面的宏来操作它* options参数可以是零个或者多个以下选项的OR逻辑运算* WNOHANG 非阻塞,如果没有符合的子进程终止,则立即放回* WUNTRACED  *      如果设定了,则设定WIFSTOPPED,及时calling process 并未追踪子进程* WCONTINUED*      如果设定了,则设定WIFCONTINUED,即使calling process并为追踪子进程,如同WUNTRACED*/int main() {pid_t pid;int status;pid = waitpid(2448, &status, WNOHANG);if (pid == -1) {perror("waitpid");} else {printf("pid=%d\n", pid);if (WIFEXITED(status)) {printf("Normal termination with exit status=%d\n", WEXITSTATUS(status));}if (WIFSIGNALED(status)) {printf("killed by signal=%d%s\n", WTERMSIG(status), WCOREDUMP(status) ? " (dump core)" : "");}}return 0;
}

利用fork(),exec,和waitpid来实现

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>int my_system(const char* cmd) {int status;pid_t pid;pid = fork();if (pid == -1) {perrorr("fork");return -1;}if (pid == 0) {const char* argv[4];argv[0] = "sh";argv[1] = "-c";argv[2] = cmd;argv[3] = NULL;execv("/bin/sh", argv);exit(-1);}if (waitpid(pid, &status, 0) == -1) {return -1;} else if (WIFEXITED(status)) {return WEXITSTATUS(status);}retrun 1;
}

获取和修改资源限制,setrlimit,getrlimit

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>/*** @brief * struct rlimit {*      rlim_t rlim_cur;   //soft limit*      rlim_t rlim_max;   //hard limit* };* * int getrlimit(int resource, struct rlimit * rlim);* int setrlimit(int resource, const struct rlimit* rlim);* @return int */int main() {struct rlimit rlim;int ret;// 取得core文件大小的限制ret = getrlimit(RLIMIT_CORE, &rlim);if (ret == -1) {perror("getrlimit");return 1;}printf("before : RLIMIT_CORE limits: soft=%ld hard=%ld\n", rlim.rlim_cur, rlim.rlim_max);// 产生如下输出// RLIMIT_CORE limits: soft=0 hard=-1  -1表示无穷大rlim.rlim_cur = 32*1024*1024;  //32MBrlim.rlim_max = RLIM_INFINITY;ret = setrlimit(RLIMIT_CORE, &rlim);if (ret == -1) {perror("setrlimit");return 1;}printf("setrlimit success!\n");ret = getrlimit(RLIMIT_CORE, &rlim);if (ret == -1) {perror("getrlimit");return 1;}printf("after: RLIMIT_CORE limits: soft=%ld hard=%ld\n", rlim.rlim_cur, rlim.rlim_max);
}

stat函数,获取文件元数据

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>int stat(const char* path, struct stat* buf);
int fstat(int fd, struct stat* buf);
int lstat(const char* path, struct stat* buf);

 

 

 使用stat获取指定文件的大小

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>int main(int argc, char* argv[]) {struct stat sb;int ret;if (argc < 2) {fprintf(stderr, "usage: %s <file>\n", argv[0]);return 1;}ret = stat(argv[1], &sb);if (ret == -1) {perror("stat error");return 1;}printf("%s is %ld bytes\n", argv[1], sb.st_size);return 0;
}

下面这段代码会使用fstat检查一个已经打开的文件是否位于一个物理设备上

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/sysmacros.h>/*** @brief 如果fd位于一个物理设备上,则返回一个正整数,如果位于一个非物理或者虚拟设备上* 则返回0,发生错误,返回-1* * @param fd * @return int */
int is_on_physical_device(int fd) {struct stat sb;int ret;ret = fstat(fd, &sb);if (ret == -1) {perror("fstat error");return -1;}return gnu_dev_major(sb.st_dev);
}int main(int argc, char* argv[]) {struct stat sb;int ret;if (argc < 2) {fprintf(stderr, "usage: %s <file>\n", argv[0]);return 1;}ret = stat(argv[1], &sb);if (ret == -1) {perror("stat error");return 1;}printf("%s is %ld bytes\n", argv[1], sb.st_size);int fd = open("buccaneer.txt", O_RDONLY);ret = is_on_physical_device(fd);if (ret == -1) {perror("is_on_physical_device faile\n");return -1;}if (ret == 0) {printf("buccaneer.txt is not on physical device!\n");} else {printf("buccaneer.txt is on physical device!\n");}return 0;
}输出:
buccaneer.txt is 149 bytes
buccaneer.txt is on physical device!

 获取文件使用权限

#include <sys/types.h>
#include <sys/stat.h>int chmod(const char* path, mode_t mode);
int fchmod(int fd, modt_t mode);

将fd文件拥有者和组设定为root

int make_root_owner(int fd) {int ret;// root的gid与uid皆为0ret = fchown(fd, 0, 0);if (ret)perror("fchown");return ret;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有哪些值得推荐的Java 练手项目?

大家好&#xff0c;我是 jonssonyan 我是一名 Java 后端程序员&#xff0c;偶尔也会写一写前端&#xff0c;主要的技术栈是 JavaSpringBootMySQLRedisVue.js&#xff0c;基于我学过的技术认真的对每个分享的项目进行鉴别&#xff0c;今天就和大家分享我曾经用来学习的开源项目…

代码随想录Day15 二叉树 LeetCodeT513 找树左下角的值 T112路径总和 T106 从中序和后序遍历构造二叉树

以上思路来自于:代码随想录 (programmercarl.com) LeetCode T513 找树左下角的值 题目思路: 本题思路:这题我们使用递归法和迭代法解决问题 注意:左下角的值不一定就是一直向左遍历的叶子结点的值,首先可以确定是最后一行的第一个叶子结点的值,也就是最大深度的叶子结点的值 定…

图像上传功能实现

一、后端 文件存放在images.path路径下 package com.like.common;import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annot…

Practical Memory Leak Detection using Guarded Value-Flow Analysis 论文阅读

本文于 2007 年投稿于 ACM-SIGPLAN 会议1。 概述 指针在代码编写过程中可能出现以下两种问题&#xff1a; 存在一条执行路径&#xff0c;指针未成功释放&#xff08;内存泄漏&#xff09;&#xff0c;如下面代码中注释部分所表明的&#xff1a; int foo() {int *p malloc(4 …

Matlab之查询子字符串在字符串中的起始位置函数strfind

一、功能 strfind函数用于在一个字符串中查找指定的子字符串&#xff0c;并返回子字符串在字符串中的起始位置。 二、语法 indices strfind(str, pattern) 其中&#xff0c;str是要进行查找的字符串&#xff0c;pattern是要查找的子字符串。 函数会返回一个由子字符串在字…

【Java 进阶篇】CSS语法格式详解

在前端开发中&#xff0c;CSS&#xff08;层叠样式表&#xff09;用于控制网页的样式和布局。了解CSS的语法格式是学习如何设计和美化网页的关键。本文将深入解释CSS的语法格式&#xff0c;包括选择器、属性和值等基本概念&#xff0c;同时提供示例代码以帮助初学者更好地理解。…

关于:未同意隐私政策,应用获取ANDROID ID问题

一、环境 Unity2018 4.21f1、Android Studio、Windows10 二、问题描述 我在提交华为应用时&#xff0c;总是提示【未同意隐私政策&#xff0c;应用获取ANDROID ID个人信息】&#xff0c;但是我已经全部去掉了&#xff0c;后面问了人工客服&#xff0c;反馈了如下信息 调用堆…

Linux 文件链接

Linux 下的文件链接有两类。一个是类似于 win 电脑的快捷方式&#xff0c;我们称为软链接&#xff0c;软链接也可以叫做符号链接。另一种是通过文件系统的 inode 连接来产生的&#xff0c;类似于 windows 电脑的复制&#xff0c;但是不产生新的文件&#xff0c;我们称为硬链接。…

UDP的报文结构和注意事项

前言 UDP&#xff08;User Datagram Protocol&#xff09;是一种无连接的传输层协议&#xff0c;它提供了一种简单的数据传输方式&#xff0c;适用于那些对可靠性要求不高的应用。本文将总结UDP的报文结构和一些使用UDP时需要注意的事项 UDP报文结构 UDP报文相对简单&#xf…

Mall脚手架总结(三) —— MongoDB存储浏览数据

前言 通过Elasticsearch整合章节的学习&#xff0c;我们了解SpringData框架以及相应的衍生查询的方式操作数据读写的语法。MongoDB的相关操作也同样是借助Spring Data框架&#xff0c;因此这篇文章的内容比较简单&#xff0c;重点还是弄清楚MongoDB的使用场景以及如何通过Sprin…

Potplayer结合cpolar内网穿透实现公网访问群晖WebDAV

把potplayer变成netflix需要几步&#xff1f; ​ 国内流媒体平台的内容让人一言难尽&#xff0c;就算是购买了国外的优秀作品&#xff0c;也总是在关键剧情上删删减减&#xff0c;就算是充了会员&#xff0c;效果如何&#xff1f; 广大网友不得不选择自己找资源下到本地&#x…

婚礼避坑指南(tips分享)

1️⃣自己买婚纱很可能比租的更省钱&#xff0c;更时髦。我是先去婚纱店看&#xff0c;玲琅满目的婚纱让我看花了眼&#xff0c;试穿了几件重工的婚纱感觉并不是自己喜欢的款式&#xff0c;穿着也不舒服&#xff0c;而且租金都要几千。自己在京东上400买的反倒特别满意。 2️…