关于linux编程:基础IO

关上文件(open函数)任何一个过程在运行时都会默认关上三个文件 规范输出stdin(键盘)规范输入stdout(显示器)规范谬误stderr(显示器)open函数原型pathname :要关上的文件门路。mode :指定要用什么权限关上文件。返回值 :关上失败则返回 -1,关上胜利则返回一个文件描述符。int open(const char *pathname, int flags); //用于关上曾经存在的文件int open(const char *pathname, int flags, mode_t mode); //用于关上不存在的文件文件权限mode创立文件时,mode用于设定新文件的权限。 该权限是以权限编码值来设定的(例如设置为 0666 )该权限受权限掩码umask的限度。 flags属性详解关上文件的形式: O_RDONLY :示意以只读形式关上。O_WRONLY :示意以只写形式关上。O_RDWR :示意以可读可写形式关上。写入数据的形式: O_APPEND :写入数据时,以在开端追加的形式写入。O_TRUNC :写入数据时,以笼罩的形式写入(即先删除原数据,再写入)如果同时应用 :O_TRUNC起作用同时不应用 :原文件内容不变(不读不写)关上不存在的文件时: O_CREAT :关上不存在的文件时,会在以后门路主动创立这个文件,如果文件存在,则会先删除这个文件再创立文件。所谓以后门路是指过程启动时所处的门路,而不是程序文件所存在的门路。读文件(read)函数原型fd :文件描述符buf :寄存读取的数据count:冀望读取的字节数返回值是理论读取的字节数。#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);写文件(write)函数原型fd :文件描述符buf :须要写入的内容count:冀望写入的字节数返回值是理论写入的字节数。#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count); C语言中的fopen、fwrite、freadc语言中的文件函数fopen等,其底层都是调用零碎的open函数等。并且 fopen 等返回值为文件指针, open 返回值是文件描述符(int类型)这样实现一种语言上的封装,实现跨平台性。文件描述符在零碎中任何时刻都存在大量的曾经关上的文件。磁盘文件中存储的不只是文件内容,还包含文件属性内存文件中存储的更多是文件属性,文件内容是迟缓的从硬盘文件中加载的。零碎调配文件描述符的办法: 以后曾经应用的文件描述符不会再次被调配,新调配的文件描述符的值是零碎中未被调配的文件描述符的值中最小的一个。文件描述符的意义每个过程中都存在一个过程管制块PCB这个PCB的构造体task_struct中存在一个文件构造体 files_struct这个文件构造体中存在一个用来存在文件指针的数组 struct file* fd_array [ ]运行过程,关上文件后,就会将文件的指针寄存在这个数组中所谓的文件描述符则是对应文件在数组中的下标。因为过程的独立性,在这个过程中将文件敞开,对其余过程没有影响。复制文件描述符dup函数介绍调用dup函数对文件描述符fd1进行复制,会返回一个新的文件描述符(留神:这个新的文件描述符fd2 在数值上不等于 fd1,然而它们都指向同一个文件)应用dup复制时,这个新的文件描述符 fd2 的值是无奈本人指定的,是由操作系统外部调配的。#include <unistd.h>int dup(int oldfd);//fd2 = dup(fd1);dup2函数介绍应用dup2 复制时,这个新的文件描述符的值是能够本人指定的。fd1 是原来的文件描述符的值,16 是人为指定新的文件描述符。如果正确,返回值fd2 就是16,如果谬误,返回值fd2 就是 -1。#include <unistd.h>int dup2(int oldfd, int newfd);//fd2 = dup2(fd1, 16);命令行中的重定向( > )Linux中的shell命令执行后,打印后果都是默认进入规范输入的(因为这些命令都是调用printf打印的),所以咱们能够间接在Linux终端看到命令执行的后果。命令行中的重定向 > 的作用: ...

August 18, 2022 · 1 min · jiezi

关于linux编程:进程概念

冯诺依曼体系结构大多数的计算机、服务器等都遵循冯诺依曼体系结构存储器用于快慢设施之间的缓冲作用,进步零碎的效率(内存能够事后装载数据) 解决数据时,必须先将数据预装载到内存中(一次性装载多条数据,由操作系统实现)在硬件和数据层面上:CPU只和内存进行交换,外设也只与内存进行交换。寄存器不仅只存在于CPU中,其余的外设中也存在。各硬件之间是用总线进行链接(IO总线、系统总线)操作系统概念操作系统本质上是一款专门搞治理的软件。操作系统包含内核(过程治理、文件治理、驱动治理)和其余程序(库函数、shell程序等)过程管制块PCBPCB:为了便于零碎形容和治理过程的运行,内核为每个过程专门创立的一个构造体对象。(一个PCB对应一个过程)PCB是过程实体的一部分,用于存储过程所需的所有信息。CPU在执行过程时,是找的PCB,再通过PCB去调用程序代码和数据。Linux中PCB的构造体是 struct task_struct{ }零碎中PCB是采纳双链表的模式链接起来的。PCB次要存储的信息: 标示符:形容此过程的惟一标示符,用于辨别其余过程(PID等)状态:休眠状态S、运行状态R如果过程是前台运行时,则会标识为 R+如果过程是后盾运行时,则会标识为 R优先级程序计数器(PC指针):保留程序中行将被执行的下一条指令的地址。内存指针:程序代码和过程相干的数据指针,和其余过程共享的内存块指针上下文数据:过程执行时处理器的寄存器中的数据。 例如:以后过程被打断,去执行另一个过程,当另一个过程执行完后要如何回到之前过程被打断的地位呢?上下文数据就是用来保留这类数据。上下文数据是保留在PCB中的。IO状态信息查看存储过程信息的文件过程信息能够通过 /proc 零碎文件夹查看(文件夹的名称就是该过程的PID)过程状态过程的5种状态就绪态R :期待被运行。(期待CPU调度)运行态R :正在运行。(占用CPU)(运行态蕴含就绪态,所以运行态能够同时有多个))僵尸态Z :父过程还在运行,子过程完结还未被回收时,子过程相干信息任然被保留着。期待态(休眠态)(浅度睡眠 & 深度睡眠):期待肯定条件进入就绪态,期待态下即便给它CPU也无奈运行。 浅度睡眠S:期待时能够被唤醒(即便没有等到某个条件,收到信号也能够被唤醒)深度睡眠D:期待时曾经不能被唤醒了,只有等到某个条件能力主动唤醒(收到信号也不能被唤醒),并且该过程不能被杀死,即便是操作系统也不行。进行态T :过程只是被临时进行了,还是能够复原的(不是过程完结了)死亡态X :过程死亡,这个状态只是一个返回状态,工作列表中是看不到这个状态的。僵尸过程子过程先于父过程完结。子过程曾经完结了,然而父过程还未帮子过程收尸(即父过程没有读取到子过程退出时返回的代码),这一个子过程就被称为僵尸过程。回收僵尸子过程办法一: 父过程能够通过应用wait或waitpid来显示回收子过程,并且获取子过程退出的状态。回收僵尸子过程办法二: 父过程本人完结时,会主动回收子过程的资源。孤儿过程父过程先于子过程完结,此时子过程就变成了孤儿过程。Linux零碎规定:所有的孤儿过程都主动成为一个非凡过程(过程1,也就是init过程)的子过程。过程优先级优先级的计算Linux中能够应用 ps -la 显示零碎过程PID和优先级Linux中理论优先级 = PRI + NI (在执行这个算法时,PRI始终都是最初始的优先级) PRI 代表这个过程的优先级,值越小越先执行。NI 代表这个过程的 nice 值(它是优先级的修改值,取值范畴 -20 ~ 19,默认为0)所以调整过程优先级是调整 nice 值。 优先级的更改终端中应用命令 sudo top 进入更改状态进入top后按 r 进入输出状态输出过程PID 而后回车再输出新的 nice 值即可过程相干性质竞争性:CPU资源很少,而过程较多,所以过程之间是具备竞争性的,为了高效实现工作,正当分配资源,于是有了优先级。独立性:多过程运行是互相独立的,独享各种资源,过程之间互不烦扰。并行:多个过程在多个CPU下同时运行。并发:多个过程在同一个CPU下采纳过程切换的形式,让多过程在宏观上实现同时运行。环境变量环境变量本质就是一个零碎级别的全局变量。PATH:指定命令的默认搜寻门路将门路导入PATH环境变量: echo PATH=$PATH: 门路HOME:指定用户的主工作目录(即用户登录到Linux时进入的默认目录)环境变量相干命令echo $环境变量 (查问相干环境变量)(echo $? 返回最近一次程序执行后的返回值)env (显示所有环境变量)unset (删除环境变量)set (显示本地定义的 shell 变量和环境变量)(本地变量只在本过程中无效)export (导入新的全局的环境变量)main函数带的参数(argv、argv、envp)argc:命令行参数个数argv:命令行参数列表envp:环境变量过程地址空间留神:过程地址空间不是理论的物理内存,而是映射出的虚拟地址(不同过程的虚拟地址是雷同的,然而理论映射的物理内存是不同的地址)每个过程都有本人的过程地址空间和对应的页表(用于示意映射关系)过程地址空间本质是物理内存中的一种内核数据结构(mm_struct)应用过程地址空间的劣势防止了野指针的呈现(野指针在页表中没有映射)防止零碎级别的越界拜访,页表只会映射以后过程的物理内存,不会映射到其余地址。对立过程的排布,即所有过程在过程地址空间中排布形式都是雷同的,并且空间范畴也是雷同的。每个过程都相当于独立进去的,更好的实现过程独立及正当应用内存空间。

August 16, 2022 · 1 min · jiezi

关于linux编程:Linux工具准备基于CentOS的云服务器

Linux软件包管理器yum性能:用于Linux下装置软件。yum软件管理器中就寄存着软件安装包 yum install -y epel-release 执行这个命令后,会装置扩大源(除了标准源的安装包外,还能够下载其余源的软件)下载软件:sudo yum install 软件名 sudo yum -y install (-y 示意下载时呈现的所有选项都容许)卸载软件:sudo yum remove 软件名Windows和云服务器互传文件(lrzsz)sudo yum install -y lrzsz (lrzsz软件是用于数据传输的)Windows传文件到云服务器:间接将文件拖动到云服务器中即可。云服务器传文件到Windows: sz 文件名 (输出命令后会弹出对话框,抉择传输到Windows的地位)留神:这个只能传输文件,不能传输文件夹。vim配置vim ~/.vimrc (关上vim的配置文件)set nu (显示行号)set autoindent (主动对齐)syntax on (设置语法检测,关键字高亮)配置vim成 VSc++ 软件的格局:(终端下输出) curl -sLf https://gitee.com/HGtz2222/Vi... -o ./install.sh && bash ./install.shLinux编辑器gcc/g++的应用gcc是用于 C 语言的编译,而 g++ 则是用于 C++ 的编译(两者应用办法类似)gcc格局: 格局一:gcc [ 选项一 ] 要编译的文件 [ 选项二 ] [ 指标文件 ] (方框内可省略)格局二:gcc [ 选项二 ] 指标文件 【要编译的文件】 (要编译的文件能够是多个)选项一: -E 示意编译器只运行到预处理阶段(头文件开展、去正文、宏替换)-S 示意编译器只进行到编译阶段(生成汇编文件)-c 示意进行汇编阶段(生成二进制文件)默认不写示意进行整个编译过程(预处理、编译、汇编、链接)生成最终可执行文件。选项二: ...

August 16, 2022 · 1 min · jiezi

关于linux编程:Linux权限概念

用户分类超级用户:root (零碎默认存在的)(领有所有权限)普通用户:本人创立 (权限受限)用户切换:su 用户名文件权限ls -l 显示的详细信息中:drwxr-xr-x(对应编码值755)共10个字符,第一个字符示意文件类型,前面9个字符三个为一组示意文件权限。文件类型(-) :示意一般文件。指文本文件和二进制文件。(d):示意文件夹或目录,directory的缩写。(c):示意字符文件(显示器、键盘等)(b):示意块设施(磁盘等)(l):示意符号连贯文件。(s):示意socket文件。(p):示意管道文件 pipe。留神:文件类型与文件的后缀无关文件权限(rwx)rwx解析:r代表可读(对应编码值为4),w代表可写(对应编码值为2),x代表可执行(对应编码值为1),-代表无权限(对应编码值为0)。 例如:drwxr-xr-x(对应编码值755)前三个字符:示意此文件的属主对文件的权限。两头三个字符:示意此文件属主所在的组对文件的权限。最初三个字符:示意其余用户对文件的权限。目录的权限(rwx)r :可读 (显示目录内容 ls)w :可写 (在目录中创立文件 touch)x :可执行 (进入目录 cd)批改文件权限(chmod)留神:root用户不受任何权限束缚。批改办法1:chmod 744 文件名 (744是权限对应的编码值)批改办法2:在原来的根底上进行批改,即减少或缩小某种权限。 例如:chmod g+x 文件名 属主所在的组减少x权限(+为减少,- 为缩小权限)三个组用户中的编码顺次为:属主u 属主所在的组g 其余用户ochown(批改文件的属主) 例如:sudo chown 属主 文件名chgrp(批改文件的组)留神:不能批改文件的其余用户 o (因为不晓得文件的其余用户具体是谁)默认权限与文件权限掩码(umask)终端中 间接umask 会显示以后umask的值(默认为0002)批改umask的办法: umask 0044 则会将 umask 的值改为0044。一般文件默认权限计算方法: 666 &(~0002)即umask中呈现的权限位在一般文件中文件夹(目录)的默认权限是: 777 & (~umask)粘滞位在Linux中,普通用户能够删除root用户的文件,减少粘滞位后,就无奈删除了。粘滞位应用办法:chmod +t 目录名 (将该目录设置为粘滞位)被设为粘滞位的目录下的所有文件只能由root用户、该文件或目录的所有者才能够删除。

August 16, 2022 · 1 min · jiezi

关于linux编程:Linux系统编程遍历目录

1. 概述在Linux C中能够通过以下3种形式进行目录的遍历 (1)应用readdir(2)应用glob(3)应用nftw2. 应用readdir遍历readdir实际上是一系列函数的汇合,它们应用的是相似于读写文件格调的API,包含的次要函数有: opendirreaddirseekdirtelldirrewinddirclosedir读写的过程如下: 调用opendir关上一个目录(参数是门路)将errno置为空(因为readdir在谬误和失常完结时都返回NULL,无奈通过返回值确定是哪种状况,须要借助于errno)在循环中调用readdir遍历整个目录(留神:readdir只遍历一层目录,如果想遍历整个目录树,须要本人应用递归进行)退出循环后应用close敞开根本的一个应用示例如下: #include <dirent.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: %s <dir>\n", argv[0]); exit(1); } DIR *dir = opendir(argv[1]); if (dir == NULL) { perror("opendir()"); exit(1); } errno = 0; struct dirent *entry; while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; printf("%s\n", entry->d_name); } closedir(dir); exit(0);}3. 应用glob遍历glob的API有点相似于解析main函数中参数argc和argv的格调,并且glob的遍历中提供了对于目录中文件名的通配符匹配,函数原型如下: ...

July 9, 2022 · 2 min · jiezi

关于linux编程:Linux系统编程四信号

一.信号概述1.1 中断中断就是字面的意思,譬如正在打游戏,手机响了,这时后中断游戏,去接手机,回来再打游戏,这就是中断。 1.2 什么是信号信号是软件中断,是在软件档次上对中断机制的一种模仿,是一种异步通信的形式 。信号是 Linux 过程间通信的最古老的形式,也是最罕用的通信形式。 1.3 信号机制过程A给过程B发送信号,过程B收到信号之前执行本人的代码,收到信号后,不论执行到程序的什么地位,都要暂停运行,去解决信号,处理完毕后再继续执行,是一种异步模式。 1.4 信号状态三种状态,产生、未决和递达。1 产生a)按键产生,如:Ctrl+c、Ctrl+zb)零碎调用产生,如:kill、raise、abort3)软件条件产生,如:定时器alarm4)硬件异样产生,如:非法拜访内存(段谬误)、除0(浮点数例外)、内存对齐出错(总线谬误)5)命令产生,如:kill命令2 未决没有被解决,产生和递达之间的状态。次要因为阻塞(屏蔽)导致该状态3 递达递送并且达到过程,信号被解决了 1.5 查看信号1)kill -l (base) zhaow@zhaow-610:~$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR111) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+338) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+843) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-1253) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-758) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-263) SIGRTMAX-1 64) SIGRTMAX// 信号编号)信号名字 2)man 7 signal ...

September 4, 2021 · 5 min · jiezi

关于linux编程:Linux系统编程三进程间通信

一.过程间通信1.1 什么是过程间通信咱们运行起来的过程,相互之间资源是独立的,不能在一个过程中间接拜访另一个过程的资源。然而很多时候不同的过程须要进行信息的交互和状态的传递等,譬如数据传输,一个过程须要将它的数据发送给另一个过程,或者多个过程间资源共享,或者一个过程须要管制另一个过程的执行,再或者,一个过程要给另一个过程发送音讯等,就须要过程间通信( IPC:Inter Processes Communication )。 1.2 过程间通信的形式过程间通信的形式有很多,文件、管道、信号、共享内存映射、音讯队列、套接字、命名管道等。这里说管道pipe,命名管道fifo,共享内存映射。 二.管道PIPE2.1 管道概述管道是一种最根本的IPC机制,也称匿名管道、无名管道,利用于有血缘关系的过程之间,实现数据传递。所有的 UNIX 零碎都反对这种通信机制。 管道的实质是一块内核缓冲区,由两个文件描述符援用,一个示意读端,一个示意写端。管道是半双工,规定数据从管道的写端流入管道,从读端流出,当两个过程都终结的时候,管道也主动隐没,管道的读端和写端默认都是阻塞的。 管道的数据一旦被读走,便不在管道中存在,不可重复读取,数据只能在一个方向上流动,若要实现双向流动,必须应用两个管道。 只能在有血缘关系的过程间应用管道 创立管道非常简单,调用pipe函数即可 2.2 pipe函数#include <unistd.h>int pipe(int pipefd[2]);性能:创立无名管道。参数: pipefd : 为 int 型数组的首地址,其寄存了管道的文件描述符 pipefd[0]、pipefd[1]。 当一个管道建设时,它会创立两个文件描述符 fd[0] 和 fd[1]。其中 fd[0] 固定用于读管道,而 fd[1] 固定用于写管道。个别文件 I/O的函数都能够用来操作管道(lseek() 除外)。返回值: 胜利:0 失败:-1代码示例 #include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>#include <sys/wait.h>/* pipe函数演示 */int main(){ int fd[2]; int ret = pipe(fd); //创立管道 if(ret<0){ //创立管道失败 perror("pipe"); return -1; } pid_t pid = fork(); if(pid < 0){ // 创立过程失败 perror("fork"); return -1; }else if(pid > 0){ // 父过程 close(fd[0]); // 父过程写入fd[1] write(fd[1],"hello",strlen("hello")); wait(NULL); }else { // 子过程读取 char buf[128]; memset(buf,0,sizeof(buf)); int n = read(fd[0],buf,sizeof(buf)); printf("%s\n",buf); }}2.3 管道的读写行为注意事项这里假设都是阻塞I/O操作,咱们应用管道须要留神以下4种非凡状况:1) 如果所有指向管道写端的文件描述符都敞开了,而依然有过程从管道的读端读数据,那么管道中残余的数据都被读取后,再次read会返回0,就像读到文件开端一样。 ...

August 22, 2021 · 3 min · jiezi

关于linux编程:Linux-系统编程二进程控制

一.过程1.1.程序和过程的关系简略来说,程序是静止的,就是咱们的可执行文件,过程是动静的,就是运行起来的程序。 1.2.并行和并发1)并行,parallel 强调同一时刻同时执行2)并发,concurrency 则指的一个时间段内去一起执行 1.3.过程的状态在五态模型中,过程分为新建态、终止态,运行态,就绪态,阻塞态,如下图 1.4.过程各个状态的切换机会 ①TASK_RUNNING(运行态):过程正在被CPU执行。当一个过程刚被创立时会处于TASK_RUNNABLE,示意己经准备就绪,正等待被调度。②TASK_INTERRUPTIBLE(可中断):过程正在睡眠(被阻塞)期待某些条件的达成。当条件达成,内核就会把过程状态设置为运行。处于此状态的过程会因为接管到信号而提前被唤醒,比方给一个TASK_INTERRUPTIBLE(可中断)状态的过程发送SIGKILL信号,这个过程将先被唤醒(进入TASK_RUNNABLE运行状态),而后再响应SIGKILL信号而退出(变为TASK_ZOMBIE进行状态),而不是从TASK_INTERRUPTIBLE状态(可中断)间接退出。③TASK_UNINTERRUPTIBLE(不可中断):处于期待中的过程,待资源满足时被唤醒,但不能够由其它过程通过信号或中断唤醒。因为不承受外来的任何信号,因而无奈用kill杀掉这些处于该状态的过程,这个状态存在的作用就是因为内核的某些解决流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于解决异步信号的流程,于是原有的流程就被中断了,这可能使某些设施陷入不可控的状态。另外处于TASK_UNINTERRUPTIBLE状态个别状况下,是十分短暂的,很难通过ps命令捕捉到。④TASK_ZOMBIE(僵死):示意过程曾经完结了,然而其父过程还没有调用wait4或waitpid()来开释过程描述符。为了父过程可能获知它的音讯,子过程的过程描述符依然被保留着。一旦父过程调用了wait4(),过程描述符就会被开释。⑤TASK_STOPPED(进行):过程进行执行。当过程接管到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等信号的时候,还有在调试的时候接管到任何信号,也会使过程进入这种状态。当接管到SIGCONT信号,会从新回到TASK_RUNNABLE。1.5 过程号过程号PID:每个过程都由一个过程号来标识,其类型为 pid_t(整型),过程号的范畴:0~32767。父过程号PPID:任何过程( 除 init 过程)都是由另一个过程创立,该过程称为被创立过程的父过程,对应的过程号称为父过程号(PPID)。过程组号PGID:过程组是一个或多个过程的汇合。他们之间互相关联,过程组能够接管同一终端的各种信号,关联的过程有一个过程组号(PGID) 1.6 过程相干函数getpid函数 #include <sys/types.h>#include <unistd.h>pid_t getpid(void);性能: 获取本过程号(PID)参数: 无返回值: 本过程号getppid函数 #include <sys/types.h>#include <unistd.h>pid_t getppid(void);性能: 获取调用此函数的过程的父过程号(PPID)参数: 无返回值: 调用此函数的过程的父过程号(PPID)getpgid函数 #include <sys/types.h>#include <unistd.h>pid_t getpgid(pid_t pid);性能: 获取过程组号(PGID)参数: pid:过程号返回值: 参数为 0 时返回以后过程组号,否则返回参数指定的过程的过程组号二.创立过程2.1 fork函数#include <sys/types.h>#include <unistd.h>pid_t fork(void);性能: 用于从一个已存在的过程中创立一个新过程,新过程称为子过程,原过程称为父过程。参数: 无返回值: 胜利:子过程中返回 0,父过程中返回子过程 ID。pid_t,为整型。 失败:返回-1。 失败的两个次要起因是: 1)以后的过程数曾经达到了零碎规定的下限,这时 errno 的值被设置为 EAGAIN。 2)零碎内存不足,这时 errno 的值被设置为 ENOMEM。应用 fork() 函数失去的子过程会将父过程复制一份(包含过程上下文、过程堆栈、关上的文件描述符、信号管制设定、过程优先级、过程组号等),所以应用fork()创立过程开销是很大的。 那么如何辨别父过程和子过程呢?那就是依据fork()返回的pid值。fork() 函数被调用一次,但返回两次,子过程的返回值是 0,而父过程的返回值则是新子过程的过程 pid。 pid_t pid = fork(); // 依据这个返回值来辨别父子过程,如同这个值小于0,那就是示意创立过程失败。代码示例 ...

August 15, 2021 · 3 min · jiezi

关于linux编程:Linux-系统编程文件IO和文件目录操作

一.零碎调用1.1 零碎调用概述零碎调用,操作系统提供给用户程序调用的一组API接口,是应用程序同零碎之间数据交互的桥梁。 Linux 的运行空间分为内核空间与用户空间,它们各自运行在不同的级别中,逻辑上互相隔离。用户过程在通常状况下不容许拜访内核数据,也无奈应用内核函数,它们只能在用户空间操作用户数据,调用用户空间函数。但存在很多状况,用户过程须要取得零碎服务,那就要利用零碎调用了。 1.2 用户态和内核态CPU能够在不同的特权级别下运行,相应的操作系统也有不同的运行级别,那就是用户态和内核态。内核态下的运行过程能够毫无限度的拜访各种资源,而在用户态下的用户过程的各种操作则都有着限度,例如用户态下的用户过程不能随便拜访内存。 属于内核的零碎调用肯定是运行在内核态下,他是操作系统内核的一部分的,以软件中断的形式从用户态切换到内核态。 1.3 零碎调用和库函数Linux 下对文件操作有两种形式:零碎调用(system call)和库函数调用(Library functions)。库函数调用(Library functions)则分为须要零碎调用和不须要零碎调用两种。 零碎调用是须要耗费工夫的,程序中频繁的应用零碎调用会升高程序的运行效率,所以库函数拜访文件的时候依据须要,会设置不同类型的缓冲区,从而缩小了间接调用 IO 零碎调用的次数,进步了拜访效率。 1.4 虚拟地址空间每个过程都会调配虚拟地址空间,在32位机器上,该地址空间为4G 。 二.文件2.1 概述Linux中,所有皆文件。文件为操作系统服务和设施提供了一个简略而统一的接口。这意味着程序齐全能够像应用文件那样应用磁盘文件、串行口、打印机和其余设施。 文件通常由两局部组成: 内容 + 属性,即治理信息,包含文件的创立批改日期和拜访权限等。属性均保留在 inode 节点中。inode - "索引节点",贮存文件的元信息,比方文件的创建者、文件的创立日期、文件的长度和文件在磁盘上寄存的地位等等。每个inode都有一个号码,操作系统用inode号码来辨认不同的文件。 目录是用于保留其余文件的节点号和名字的文件,每个数据项为指向文件节点的链接。 2.2 文件描述符咱们能够零碎调用中 I/O 的函数(I:input,输出;O:output,输入),对文件进行相应的操作( open()、close()、write() 、read() 等)。 关上现存文件或新建文件时,零碎(内核)会返回一个文件描述符,文件描述符用来指定已关上的文件。这个文件描述符相当于这个已关上文件的标号,文件描述符是非负整数,是文件的标识,操作这个文件描述符相当于操作这个描述符所指定的文件。 程序运行起来后(每个过程)都有一张文件描述符的表,规范输出、规范输入、规范谬误输出设备文件被关上,对应的文件描述符 0、1、2 记录在表中。程序运行起来后这三个文件描述符是默认关上的。 1)0: 规范输出 STDIN_FILENO2)1: 规范输入 STDOUT_FILENO3)2: 规范谬误 STDERR_FILENO三.罕用文件IO操作3.1 open、close函数open函数:创立一个新的文件描述符(文件或设施)。 #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);性能: 关上文件,如果文件不存在则能够抉择创立。参数: pathname:文件的门路及文件名 flags:关上文件的行为标记,必选项 O_RDONLY, O_WRONLY, O_RDWR mode:这个参数,只有在文件不存在时无效,指新建文件时指定文件的权限返回值: 胜利:胜利返回关上的文件描述符 失败:-1flags必选项: ...

July 31, 2021 · 6 min · jiezi

关于linux编程:Linux编程入门正点原子Linux驱动开发指南学习2021W27

(3)U-Boot 启动流程详解lowlevel_init 函数详解函数 lowlevel_init 在文件 arch/arm/cpu/armv7/lowlevel_init.S 中定义 #include <asm-offsets.h>#include <config.h>#include <linux/linkage.h>ENTRY(lowlevel_init) /* * Setup a temporary stack. Global data is not available yet. */ ldr sp, =CONFIG_SYS_INIT_SP_ADDR /* 宏定义在include/configs/mx6ullevk.h sp 指向 0X91FF00,这属于 IMX6UL/IMX6ULL 的外部 ram*/ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */#ifdef CONFIG_SPL_DM mov r9, #0#else /* * Set up global data for boards that still need it. This will be * removed soon. */#ifdef CONFIG_SPL_BUILD ldr r9, =gdata#else sub sp, sp, #GD_SIZE /* GD_SIZE = 248 ,定义在 generic-asm-offsets.h*/ bic sp, sp, #7 /*八字节对齐*/ mov r9, sp /*SP = 0X0091FF00-248=0X0091FE08*/#endif#endif /* * Save the old lr(passed in ip) and the current lr to stack */ push {ip, lr} /* * Call the very early init function. This should do only the * absolute bare minimum to get started. It should not: * * - set up DRAM * - use global_data * - clear BSS * - try to start a console * * For boards with SPL this should be empty since SPL can do all of * this init in the SPL board_init_f() function which is called * immediately after this. */ bl s_init /*跳转到 s_init ,实现初始化*/ pop {ip, pc} /*弹出堆栈,并将lr的值返回给PC*/ENDPROC(lowlevel_init)s_init 函数详解上一节的初始化跳转到 s_init ,该函数在定义在 arch/arm/cpu/armv7/mx6/soc.c 的808行。 ...

July 3, 2021 · 6 min · jiezi

关于linux编程:Linux编程入门正点原子Linux驱动开发指南学习2021W26

十一、U-Boot 启动流程详解(1)链接脚本 u-boot.lds 详解在编译实现当前就会在 uboot 根目录下生成 u-boot.lds文件,从该文件来剖析 U-boot 启动流程。 /*1. 第 3 行为代码以后入口点: _start, _start 在文件 arch/arm/lib/vectors.S 中有定义2. __image_copy_start 这个变量是在 u-boot-spl.lds 文件里定义的,是这个链接文件的 .text 段的开始地址*/OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{ . = 0x00000000; . = ALIGN(4); .text : { *(.__image_copy_start) *(.vectors) arch/arm/cpu/armv7/start.o (.text*) *(.text*) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data*) } . = ALIGN(4); . = .; . = ALIGN(4); .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); } . = ALIGN(4); .image_copy_end : { *(.__image_copy_end) } .rel_dyn_start : { *(.__rel_dyn_start) } .rel.dyn : { *(.rel*) } .rel_dyn_end : { *(.__rel_dyn_end) } .end : { *(.__end) } _image_binary_end = .; . = ALIGN(4096); .mmutable : { *(.mmutable) } .bss_start __rel_dyn_start (OVERLAY) : { KEEP(*(.__bss_start)); __bss_base = .; } .bss __bss_base (OVERLAY) : { *(.bss*) . = ALIGN(4); __bss_limit = .; } .bss_end __bss_limit (OVERLAY) : { KEEP(*(.__bss_end)); } .dynsym _image_binary_end : { *(.dynsym) } .dynbss : { *(.dynbss) } .dynstr : { *(.dynstr*) } .dynamic : { *(.dynamic*) } .plt : { *(.plt*) } .interp : { *(.interp*) } .gnu.hash : { *(.gnu.hash) } .gnu : { *(.gnu*) } .ARM.exidx : { *(.ARM.exidx*) } .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }}在文件 arch/arm/lib/vectors.S 中,能够看到定义了独自的段.section ".vectors", "ax"。_start 前面就是中断向量表。 ...

June 26, 2021 · 4 min · jiezi

关于linux编程:Linux编程入门正点原子Linux驱动开发指南学习2021W25

十、U-Boot 顶层 Makefile 详解这里参考一个博主的文章 (1)编译后的 U-Boot 文件构造编译后的 U-Boot 目录下有如下文件夹和文件,作用备注在前面| U-boot 自带的目录├── api ---与硬件无关的 API 函数。├── arch ---与架构体系无关的代码。├── board ---不同板子(开发板)的定制代码。├── cmd ---命令相干代码。├── common ---通用代码。├── configs ---配置文件。├── disk ---磁盘分区相干代码。├── doc ---文档。├── drivers ---驱动代码。├── dts ---设施树。├── examples ---示例代码。├── fs ---文件系统。├── include ---头文件。├── lib ---库文件。├── Licenses ---许可证相干文件。├── net ---网络相干代码。├── post ---上电自检程序。├── scripts ---脚本文件。├── test ---测试代码。└── tools ---工具文件夹。 | 编译生成├── .config 配置文件,重要的文件。├── .u-boot.bin.cmd 一系列的文件,用于保留着一些命令。├── .u-boot.cfg.cmd├── .u-boot.imx.cmd├── .u-boot.lds.cmd├── .u-boot-nodtb.bin.cmd├── .u-boot.srec.cmd├── .u-boot.sym.cmd├── System.map 零碎映射文件├── u-boot* 编译进去的 u-boot 文件。├── u-boot.bin 生成的一些 u-boot 相干文件├── u-boot.cfg├── .u-boot.cfg.d├── .u-boot.cmd├── u-boot.imx├── u-boot.lds├── u-boot.map├── u-boot-nodtb.bin├── u-boot.srec├── u-boot.sym└── .u-boot.sym.cmd ...

June 20, 2021 · 11 min · jiezi

关于linux编程:Linux编程入门正点原子Linux驱动开发指南学习2021W24

九、C语言版LED试验工程治理工程治理次要是在 Makefile 中会对一些源文件的地址援用和输入文件地址定位,依照学习指南的给出的公共构造如图,对于该目录构造的工程,编写Makefile如下。 CROSS_COMPILE ?= arm-linux-gnueabihf- # ?= 如果没有定义,则定义为TARGET ?= bspCC := $(CROSS_COMPILE)gccLD := $(CROSS_COMPILE)ldOBJCOPY := $(CROSS_COMPILE)objcopyOBJDUMP := $(CROSS_COMPILE)objdump# \ 是换行符,示意下一行与这一行为同一行。INCDIRS 是所有头文件的文件夹INCDIRS := imx6ul \ bsp/clk \ bsp/led \ bsp/delay # SRCDIRS 源代码所在的文件夹 SRCDIRS := project \ bsp/clk \ bsp/led \ bsp/delay # 应用 patsubst 函数把 INCDIRS 中的每一个文件夹替换成 -I $(folder) 的格局,因为Makefile 指明头文件目录时 须要在后面加上 -I INCLUDE := $(patsubst %, -I %, $(INCDIRS))# 先应用 foreach 函数取出SRCDIRS每个文件,而后用wildcard 函数匹配出.S结尾的文件,匹配出的文件带目录门路SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))# 先应用 notdir 函数去除门路SFILENDIR := $(notdir $(SFILES))CFILENDIR := $(notdir $(CFILES))# 先应用变量替换,把SFILENDIR外面的.S文件替换成.o文件,而后用patsubst 给这些文件带上门路 obj/SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))OBJS := $(SOBJS) $(COBJS)# 指定搜寻目录VPATH,应用 VPATH 指明源文件门路,如果不指明,make只会在以后的目录中去找寻依赖文件和指标文件VPATH := $(SRCDIRS).PHONY: clean# bsp.bin 依赖 obj/ 目录下的 .o 文件,因为以后obj/目录下还为空,会执行上面的依赖 $(TARGET).bin : $(OBJS) $(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(OBJCOPY) -O binary -S $(TARGET).elf $@ $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis# obj/ 目录上面的 .o 文件依赖于 .S 文件$(SOBJS) : obj/%.o : %.S $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<$(COBJS) : obj/%.o : %.c $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $< clean: rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)这里的链接脚本与之前的基本一致,就是要留神 .text 外面的 文件要加门路 obj/start.o ...

June 12, 2021 · 2 min · jiezi

关于linux编程:Linux编程入门正点原子Linux驱动开发指南学习2021W23

五、 ARM汇编根底对于 Cortex-A 芯片来讲,大部分芯片在上电当前 C 语言环境还没筹备好,所以前一部分程序必定是汇编的。这部分汇编用来初始化堆栈(即堆栈指针SP),对于某些芯片自身没有 RAM,或者外部 RAM 不凋谢给用户应用,用户代码须要在 DDR 中运行,因而一开始要用汇编来初始化 DDR 控制器。这部分波及到的指令不是很简单,可能就十几个指令。 (1) GNU汇编语法不同编译器应用的汇编语法略有不同,咱们要编写的是 ARM 汇编,编译应用的 GCC 穿插编译器,所以咱们的汇编代码要合乎 GNU 语法。GNU 汇编语法实用于所有的架构,并不是 ARM 独享的, GNU 汇编由一系列的语句组成,每行一条语句,每条语句有三个可选局部:label: instruction @ comment label 即标号,示意地址地位,有些指令后面可能会有标号,这样就能够通过这个标号失去指令的地址,标号也能够用来示意数据地址。留神 label 前面的“:”,任何以“:”结尾的标识符都会被辨认为一个标号。instruction 即指令,也就是汇编指令或伪指令。@符号,示意前面的是正文,就跟 C 语言外面的“/”和“/”一样,其实在 GNU 汇编文件中咱们也能够应用“/”和“/”来正文。comment 就是正文内容。留神! ARM 中的指令、伪指令、伪操作、寄存器名等能够全副应用大写,也能够全副应用小写,然而不能大小写混用。 用户能够应用.section 伪操作来定义一个段,格局如下.section .testsection @定义一个 testsetcion 段另外汇编零碎预约义了一些段名, .text 示意代码段。.data 初始化的数据段。.bss 未初始化的数据段。.rodata 只读数据段。汇编程序的默认入口标号是 _start ,不过咱们也能够在链接脚本中应用 ENTRY 来指明其它的入口点,上面的代码就是应用_start 作为入口标号: global _start_start:ldr r0, =0x12 @r0=0x12下面代码中 .global 是伪操作,示意 _start 是一个全局标号,相似 C 语言外面的全局变量一样,常见的伪操作有: .byte 定义单字节数据,比方.byte 0x12。.short 定义双字节数据,比方.short 0x1234。.long 定义一个 4 字节数据,比方.long 0x12345678。.equ 赋值语句,格局为: .equ 变量名,表达式,比方.equ num, 0x12,示意 num=0x12。.align 数据字节对齐,比方: .align 4 示意 4 字节对齐。.end 示意源文件完结。.global 定义一个全局符号,格局为: .global symbol,比方: .global _start。GNU 汇编同样也反对函数,函数格局如下: ...

June 6, 2021 · 5 min · jiezi

关于linux编程:awk用法

awk牛批嘛? 不便嘛? 你理解嘛? 来看看吧 如果有一个大文件你要取出文件当中的某一列,或者某一个值,怎么取呢? 文件:test.txt算出你想取出的列$x 执行如下命令 输入到一个新的文件cat test.txt | awk "{print $x}" > newfile.txt 须要计算某个字段的和呢? 算出平响? 求和:cat test.txt | awk "{sum += $x} END {print sum}" 算出平响:cat test.txt | awk "{sum += $x} END {print 'sum = ' sum; print 'average = ' sum/NR }" 后续持续学习~~~

May 31, 2021 · 1 min · jiezi

关于linux编程:Linux编程入门正点原子Linux驱动开发指南学习2021W22

之前原本想间接看Padavan的源码,前面发现好多Linux零碎函数十分含糊,还是须要零碎的学习一下。当初就从零开始学习,在这记录一下学习的轨迹。之前为了编译Padavan的零碎,装置了一个Ubuntu 16.4的零碎,刚好这外面比拟洁净,尽管有一些常识之前都理解过了,我还是依照开发指南介绍的一步步来做吧。在这里举荐一个Linux笔记,外面有罕用的Linux命令,很不便。 一、 Linux 基本操作创立编程的文件夹,W22代表第22周,现打算每周更新一篇。mkdir -r C_Program//W22配置vim的一些参数。无心中发现在github外面搜vim config会有很多我的项目能够把vim配置的很花哨,我临时还是依照简略的来吧,这里举荐一个VIM配置, 我的配置如下: " 在家目录下创立 .vimrc 文件,这样这个配置不会影响其余用户vi ~/.vimrc" 配置如下set tabstop=4 " 设置softtabstop有一个益处是能够用Backspace键来一次" 删除4个空格. softtabstop的值为正数,会应用shiftwidth" 的值,两者保持一致,不便对立缩进.set softtabstop=-1 " 主动缩进时,缩进长度为4set shiftwidth=4 set noexpandtab set nu set autoindent 来实现第一个hello world cheney@ubuntu:~/C_Program/W22$ gcc hellow_world.c -o hellow_worldcheney@ubuntu:~/C_Program/W22$ lshellow_world hellow_world.ccheney@ubuntu:~/C_Program/W22$ ./hellow_world Hello World! 二、 MakefileMakefile 记录一些重点吧,这个之前也也些许理解,举荐一个视频 [linux从零到精通] gcc和Makefile 命令列表中的每条命令必须以 TAB 键开始,不能应用空格!执行过程 make 命令会在当前目录下查找以 Makefile(makefile 其实也能够)命名的文件。当找到 Makefile 文件当前就会依照 Makefile 中定义的规定去编译生成最终的指标文件。当发现指标文件不存在,或者指标所依赖的文件比指标文件新(也就是最初批改工夫比指标文件晚)的话就会执行前面的命令来更新指标。自动化变量自动化变量就是这种变量会把模式中所定义的一系列的文件主动的挨个取出,直至所有的合乎模式的文件都取完,自动化变量只应该呈现在规定的命令中伪指标个别的指标名都是要生成的文件,而伪指标不代表真正的指标名,在执行 make 命令的时候通过指定这个伪指标来执行其所在规定的定义的命令。函数Makefile 中的函数是曾经定义好的,咱们间接应用,不反对咱们自定义函数# Makefile根本规格main: main.o input.o calcu.o gcc main.o input.o calcu.o -o main main.o: main.c gcc -c main.cinput.o: input.c gcc -c input.ccalcu.o: calcu.c gcc -c calcu.cclean: rm -rf main.o input.o calcu.o rm -rf main(1) Makefile变量=(替换,以最初面前面呈现的为最终值)+=(追加,能够在原变量上减少):=(恒等于,常量)?= (若之前没有赋值,则赋值)$(var) (援用变量) ...

May 30, 2021 · 3 min · jiezi

关于linux编程:并发编程记录单线程多线程多进程对比

Python实现并发编程 多线程多过程协程(生成器)并发编程的基本概念 串行:一个人在一段时间段内只能干一件事件(吃完饭后能力看电视) 并行:一个人在一段时间内同时干多件事件(边吃饭边看电视) 在Python中,多线程 和 协程 尽管是严格上来说是串行,但却比个别的串行程序执行效率高得很。 个别的串行程序,在程序阻塞的时候,只能干等着,不能去做其余事。就如同,电视上播完正剧,进入广告工夫,咱们却不能去趁广告工夫是吃个饭。对于程序来说,这样做显然是效率极低的,是不合理的。 当然,利用广告工夫去做其余事,灵便安顿工夫。这也是咱们多线程和协程 要帮咱们要实现的事件,外部正当调度工作,使得程序效率最大化。 尽管 多线程 和 协程 曾经相当智能了。但还是不够高效,最高效的应该是一心多用,边看电视边吃饭边聊天。这就是咱们的 多过程 能力做的事了。 单线程、多线程、多过程比照 试验配置 操作系统 cpu核数 内存 硬盘ubuntu 18.04 4 8G SSD【文章福利】须要C/C++ Linux服务器架构师学习材料加群1106747042(材料包含C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等) 开始比照之前定义四种类型的场景 CPU计算密集型一些过程绝大多数工夫在计算上,称为计算密集型(CPU密集型)computer-bound。一些大量循环的代码(例如:图片解决、视频编码、人工智能等)就是CPU密集型磁盘IO密集磁盘io,顾名思义就是磁盘的输入输出。即向磁盘写入数据和从磁盘读取数据网络IO密集有一些过程则在input 和output上破费了大多工夫,称为I/O密集型,I/O-bound。比方搜寻 引擎大多工夫是在期待相应【模仿】IO密集 import timeimport requests CPU计算密集型def cpu_count(a=1,b=1): # 使程序实现150万次计算c = 0while c < 500000: c += 1 a += a b += b磁盘读写IO密集def io_disk(): with open('./IOtest.txt','w') as f: for i in range(5000000): f.write('磁盘-io-测试') 网络IO密集型headers = { "User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)"}url = 'https://www.baidu.com/'def io_request(): ...

May 28, 2021 · 2 min · jiezi

linuxC基础系列内存管理野指针md

野指针概述野指针通常指的是指针变量中保留的值不会死一个非法的内存地址,但又对其拜访。须要留神的是野指针不是空指针,而是指向内存不可用的指针。C语言中对于空指针(NULL)是能够判断进去的,然而野指针是无奈判断一个非空指针是否为野指针。 野指针个别的起源如下: 部分指针变量没有初始化#include <string.h>int main(){ char *p; strcpy(p,"haha"); // 野指针 return 0;}应用已开释的指针int main(){ int *p = (int *)malloc(sizeof(int)*5); free(p); *p = 1; // 野指针 return 0;}指针所指向的内存空间在应用前被销毁#include<stdio.h>char *fun(){ char p[] = "haha"; return p;} int main(){ char *p = fun(); printf("%s\n",p); // 野指针 return 0;}指针经典谬误①被指向的变量没有初始化②没有为指针指向的内存调配足够的内存 struct Demo{ int *p;} int main(){ struct Demo d1,d2; int i; for(i = 0; i < 10; i++){ d1.p[i] = i; // 未初始化 } d2.p = (int *)calloc(5,sizeof(int)); for(i = 0; i < 10; i++){ d2.p[i] = i; // 越界,没有调配足够的空间 } free(d2.p); return 0;}内存调配胜利但没有初始化#include<stdio.h>#include<malloc.h>int main(){ char *s = (char *)malloc(10); printf("%s\n",s); // 字符串以 '\0' 为结束符,如不初始化,则未知 '\0'在哪。 free(s); return 0;}数组越界#include<stdio.h> void fun(int a[10]){ int i; for(i = 0; i < 10 ;i++){ a[i] = i; // 越界 printf("%d\n",a[i]); }} int main(){ int a[5]; fun(a); return 0;}内存透露void fun(unsigned int size){ int *p = malloc(sizeof(int) * size); int i; if(size % 2 != 0){ return ; // 未开释已申请的内存 } for(i = 0; i < size ;i++){ p[i] = i; printf("%d\n",p[i]); } free(p);}此处可表明,函数设计时最好是单入口单进口。 ...

July 10, 2020 · 2 min · jiezi

APUE-学习记录-20200708

3.13 函数sync、fsync和fdatasync传统的UNIX零碎实现在内核中设有缓冲区高速缓存或页高速缓存,大多数磁盘I/O都通过缓冲区进行。当向文件写入数据时,内核通常先将数据复制到缓冲区,而后排入队列,晚些时候再写入磁盘。这种形式被成为提早写。 通常,当内核须要重用缓冲区来寄存其余磁盘块数据时,它会把所有提早写数据块写入磁盘。为了保障磁盘上理论文件系统与缓冲区中内容的一致性,UNIX零碎提供了sync、fsync和fdatasync三个函数。 #include <unistd.h>int fsync(int fd);int fdatasync(int fd); // 返回值:若胜利,返回0;若出错,返回-1void sync(void);sync只是将所有批改过的块缓冲区排入写队列,而后就返回,它并不期待理论写磁盘操作完结。 通常,称为update的零碎守护过程周期性地调用(个别每隔30秒)sync函数。这就保障了定期flush内核的块缓冲区。命令sync也调用sync函数。 fsync函数只对有文件描述符fd指定的一个文件起作用,并且期待写磁盘操作完结才返回。fsync可用于数据库这样的应用程序,这种应用程序须要确保批改过的块立刻写到磁盘上。 fdatasync函数相似于fsync,但它只影响文件的数据局部。而除数据外,fsync还会同步更新文件的属性。 3.14 函数fcntlfcntl函数能够扭转曾经关上文件的属性。 #include <fcntl.h>int fcntl(int fd, int cmd, .../* int arg */); // 返回值:若胜利,则依赖于cmd;若出错,返回-1在本节的各实例中,第3个参数总是一个整数,与下面所示的函数原型中的正文局部对应。然而在14.3节阐明记录锁时,第3个参数是指向一个构造的指针。 fcntl函数有以下5种性能: 复制一个已有的描述符(cmd=F_DUPFD或FDUPFD_CLOEXEC)获取/设置文件描述符标记(cmd=F_GETFD或F_SETFD)获取/设置文件状态标记(cmd=F_GETFL或F_SETFL)获取/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)获取/设置记录锁(cmd=F_GETLK、F_SETLK或F_SETLKW)F_DUPFD:复制文件描述符fd/新文件描述符作为函数值返回。他是尚未关上的各描述符中大于或等于第3个参数值(取为整型值)中各值的最小值。新描述符与fd共享同一文件表项。然而,新描述符有它本人的一套文件描述符标记,其FD_CLOEXEC文件描述符标记被革除,这示意该描述符在exec时仍放弃无效。F_DUPFD_CLOEXEC:复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符标记的值,返回新文件描述符。F_GETFD:对应于fd的文件描述符标记作为函数值返回。以后只定义了一个文件描述符编制FD_CLOEXEC。F_SETFD:对于fd设置文件描述符标记。新标记按第3个参数(取为整型值)设置。F_GETFL:对应于fd的文件状态标记作为函数值返回。F_SETFL:将文件状态标记设置为第3个参数的值(取为整型值)。能够更改的几个标记是O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC和O_ASYNC。F_GETOWN:获取以后接管SIGNO和SIGURG信号的过程ID或过程组ID。F_SETOWN:设置接管SIGNO和SIGURG信号的过程ID或过程组ID。正的arg指定一个过程ID,负的arg示意等于arg绝对值的一个过程组ID。fcntl的返回值与命令无关。如果出错,所有的命令都返回-1,如果胜利则返回某个其余值。下列4个命令有特定的返回值:F_DUPFD、F_GETFD、F_GETFL、和F_GETOWN。第1个命令返回新的文件描述符,第2个和第3个命令返回响应的标记,最初一个命令返回一个整的过程ID或负的过程组ID。

July 9, 2020 · 1 min · jiezi

APUE-学习记录-20200706

3.12 函数dup和dup2#include <unistd.h>int dup(int fd);int dup2(int,fd, int fd2); // 返回值:若成功,返回新的文件描述符;若出错,返回-1由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。对于dup2,可以用fd2参数执行新描述符的值。如果fd2已经打开,则先将其关闭。若fs等于fd2,则dup2返回fd2,而不关闭它。否则,fd2的FD_CLOEXEC文件描述符标志就被清除,这样fd2在进程调用exec时是打开状态。这些函数返回的新文件描述符与参数fd共享同一个文件表项,如下图所示:在此图中,我们假定进程启动时执行了: newfd = dup(1);当此函数开始执行时,假定下一个可用的描述符是3(这是非常可能的,因为0,1和2都由shell打开)。因为两个描述符指向同一文件表项,所以它们共享同一文件状态标志(读、写、追加等)以及同一当前文件偏移量。 每个文件描述符都有它自己的一套文件描述符标志。 复制一个描述符的另一种方法是使用fcntl函数。实际上,调用 dup(fd);等效于 fcntl(fd, F_DUP_FD, 0);而调用 dup2(fd, fd2);等效于 close(fd2);fcntl(fd, F_DUPFD, fd2);后一种情况下,dup2并不完全等同于close加上fcntl。它们之间的区别如下: 1. dup2是一个原子操作,而close和fcntl包括两个函数调用。有可能在close和fcntl之间调用了信号捕获函数,它可能修改文件描述符。如果不同的线程改变了文件描述符的话也会出现相同的问题。2. dup2和fcntl有一些不同的errno。

July 8, 2020 · 1 min · jiezi

APUE-学习记录-20200630

3.11 原子操作追加到一个文件考虑一个进程,他要将数据追加到一个文件尾端。早期的UNIX系统版本并不支持open的O_APPEND选项,所以程序被编写程下列形式: if (lseek(fd, OL, 2))

June 30, 2020 · 1 min · jiezi

APUE-学习记录-20200629

3.10 文件共享UNIX系统支持在不同进程见共享打开文件。在介绍dup函数之前,先要说明这种共享。 内核使用3种数据结构表示打开文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能的影响。 每个进程在进程表中都有一个记录项,记录项中包含一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:a. 文件描述符标志(close_on_exec);b. 指向一个文件表项的指针。内核为所有打开文件维持一张文件表。每个文件表项包含:a. 文件状态标志(读、写、添写、同步和非阻塞等);b. 当前文件偏移量;c. 指向该文件v节点表项的指针。每个打开文件(或设备)都有一个v节点(v-node)结构。v阶段包含了文件类型和对此文件进行各种操作函数的指针。对于大多数文件,v节点还包含了该文件的i节点(i-node,索引节点)。这些信息是在打开文件时从磁盘上读入内存的。所以,文件的所有相关信息都是随时可用的。Linux没有使用v节点,而是使用了通用i节点结构。我们忽略了哪些不影响讨论的实现细节。例如,打开文件描述符表可存放在用户空间,而非进程表中。这些表也可以用多种方式实现,不必一定是数组。 下图显示了一个进程对应的3张表之间的关系。该进程有两个不同的打开文件:一个文件从标准输入打开(文件描述符0),另一个从标准输出打开(文件描述符为1)。 如果两个独立进程各自打开了同一个文件,则有下图关系: 我们假定第一个进程在文件描述符3上打开该文件,而另一个进程在文件描述符4上打开该文件。打开该文件的每一个进程都获得自己的文件表项,但对一个给定的文件只有一个v节点表项。之所以每个进程都获得自己的文件表项,是因为这可以是每个进程都有它自己的对该文件的当前偏移量。

June 29, 2020 · 1 min · jiezi

APUE-学习记录-20200628

3.7 函数read调用read函数从打开文件中读数据。 #include <unistd.h>ssize_t read(int fd, void *buf, size_t nbytes); // 返回值:读到的字节数,若已到文件尾,返回0;若出错,返回-1如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0.有多种情况可使实际读到的字节数少于要求读的字节数: 读普通文件时,在读要求字节数之前已到达了文件尾端。当从终端设备读时,通常一次最多读一行。当从网络读时,网络中的缓冲机制可能造成但绘制小于所要求读的字节数。当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数。当从某些面向记录的设备(如磁带)读时,一次最多返回一个记录。当一信号造成中断,而已经读了部分数据量时。读操作从文件的当前偏移量处开始,在成功返回之前,该偏移量将增加实际读到的字节数。 POSIX.1从几个方面对read函数的原型做了更改。经典的原型定义是: int read(int fd, char *buf, unsigned nbytes);首先,为了与ISO C一致,第二个参数由char *改为void *。在ISO C中,类型void *用于便是通用指针。其次,返回值必须是一个带符号整型(ssize_t),以保证能够返回正整数字节数、0或-1。最后,第三个参数在历史上是一个无符号整型,这允许一个16位的实现一次读或写的数据可以多达65534个字节。3.8 函数write调用write函数向打开文件中写数据。 #include <unistd.h>ssize_t write(int fd, void * buf, size_t nbytes); // 返回值:若成功,返回已写的字节数;若出错,返回-1其返回值通常与参数nbytes值相同,否则表示出错。write出错的一个常见原因是磁盘已写满,或者超过了一个给定进程的文件长度限制。 对于普通文件,写操作从文件的当前偏移量处开始。如果在打开文件时,制定了O_APPEND选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处。在一次成功写之后,该文件偏移量增加实际写的字节数。 3.9 I/O的效率Page 58 示例:只使用read和write函数复制一个文件。 #include "apue.h"#define BUFFSIZE 4096int main(void){ int n; char buf[BUFFSIZE]; while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) if(write(STDOUT_FILENO, buf, n) != n) err_sys("write error"); if(n < 0) err_sys("read error"); exit(0);}关于该程序应注意以下几点: ...

June 28, 2020 · 1 min · jiezi

APUE-学习记录-20200624

3.4 函数Creat#include <fcntl.h>int creat(const char *path, mode_t mode); // 返回值:若成功,返回为只写打开额文件描述符;若出错,返回-1此函数等效于: open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);creat的一个不足之处是它以只写方式打开所创建的文件。在提供open的新版本之前,如果要创建一个临时文件,并要先写文件,然后又读该文件,则必须先调用creat、close,然后再调用open,现在则可用以下方式调用open实现: open(path, O_EDWR | O_CREAT | O_TRUNC, mode);3.5 函数close调用close函数可以关闭一个打开文件。#include <unistd.h>int close(int fd); // 返回值:若成功,返回0;若出错,返回-1当关闭一个文件时,还会释放该进程加在该文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有的打开文件。 3.6 函数lseek每个打开文件都有一个与其相关联的“当前文件偏移量”。它通常是一个非负整数,用来度量从文件开始处计算的字节数。通常,读、写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。按系统默认的情况,当打开一个文件时,除非指定O_APPEND选项,否则该偏移量被设置为0. 可以调用lseek显式为一个打开文件设置偏移量。 #include <unistd.h>off_t lssek(int fd, off_t offset, int whence); // 返回值:若成功,返回新的文件偏移量;若出错,返回-1对参数offset的理解与参数whence的值有关。 若whence是SEEK_SET,则将该文件的偏移量设置为距文件开始处offset个字节。若whence是SEEK_CUR,则将该文件的偏移量设置为其当前值加offset,offset可为正或负。若whence是SEEK_END,则将该文件的偏移量设置为文件长度加offset,offset可为正或负。若lssek成功执行,则返回新的文件偏移量,为此可以用下列方式确定打开文件的当前偏移量: off_t currpos;currpos = lseek(fd, 0, SEEK_CUR);这种方法也可以用来确定所涉及的文件是否可以设置偏移量。如果文件描述符指向的是一个管道、FIFO、或网络套接字,则lseek返回-1,并将errno设置为ESPIPE。 Page 54实例 #include "apue.h"int main(void){ if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1) printf("cannot seek\n"); else printf("seek OK\n"); exit(0);}使用终端调用此程序,则可得: ...

June 24, 2020 · 1 min · jiezi

APUE-学习记录-20200622

3.2 文件描述符对于内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,使用open或creat返回的文件描述符,将其作为参数传送给read和write。 UNIX系统shell将文件描述符0与进程的标准输入关联,文件描述符1与标准输出关联,文件描述符2与标准错误关联。在符合POSIX.1的应用程序,应当将0,1,2替换成符号STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO来提高可读性。这些常量在头文件<unistd.h>中定义。文件描述符的变化范围是0~OPEN_MAX-1。 3.3 函数open和openat调用open或openat函数可以打开或创建一个文件。 #include <fcntl.h>int open(const char *path, int pflag, .../*mode_t mode */);int openat(int fd, const char *path, int oflag, ... /* mode_t mode */);...表示余下的参数的数量及其类型是可变的。对于open函数而言,仅当创建新文件时才使用最后一个参数。 path参数是要打开或创建文件的名字。oflag参数可用来说明此函数的多个选项,用下列一个或多个常量进行或运算构成oflag参数。 O_RDONLY 只读打开O_WRONLY 只写打开O_EDWR 读写打开

June 22, 2020 · 1 min · jiezi

APUE-学习记录-20200618

1.5输入和输出1. 文件描述符文件描述符通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。当内核打开一个现有文件或创建一个新文件时,都返回一个文件描述符。在读写文件时,可以使用文件描述符。 2. 标准输入、标准输出和标准错误每当运行一个新程序时,shell都会为其打开3个文件描述符,即标准输入、标准输出和标准错误,这三个描述符都链接到终端。 3. 不带缓冲的I/O函数open、read、write、lseek、close提供了不带缓冲的I/O,这些函数都使用文件描述符。 Page7 实例 #include "apue.h"#define BUFFERSIZE 4096int main(void){ int n; char buf[BUFFERSIZE]; while((n = read(STDIN_FILENO, buf, BUFFERSIZE)) > 0) if(write(STDOUT_FILENO, buf, n) != n) err_sys("write error"); if (n < 0) err_sys("read error"); exit(0);}说明: STDIN_FILENO和STDOUT_FILENO定义在unistd.h中,指定了标准输入和标准输出的文件描述符。read函数返回读取的字节数,此值用作要写的字节数。当到达输入文件末尾时,read返回0,程序停止。调用方法: ./a.out > data./a.out < infile > outfile4. 标准I/O标准I/O为不带缓冲的I/O函数提供了带缓冲的接口。 Page8 实例 #include "apue.h"int main(void){ int c; while((c = getc(stdin)) != EOF) if(putc(c, stdout) == EOF) // putc() returns EOF when error ocurrs err_sys("output error"); if(ferror(stdin)) err_sys("input error"); exit(0);}1.6 程序和进程1. 程序程序是一个存储在磁盘上某个目录中的可执行文件,内核使用exec函数将程序度如内存,并执行程序。 ...

June 18, 2020 · 1 min · jiezi

APUE-学习记录-20200617

准备工作: APUE第三版源代码下载链接:http://apuebook.com/code3e.html安装了Linux Mint虚拟机,安装vmware-tool安装libc6-dev libbsd-devmake生成libapue.aPage4 实例 #include "apue.h"#include <dirent.h>int main(int argc, char *argv[]){ DIR *dp; struct dirent *dirp; if(argc != 2) err_quit("usage: ls directory_name"); if((dp = opendir(argv[1])) == NULL) err_sys("can't open %s", argv[1]); while((dirp = readdir(dp)) != NULL) printf("%s\n", dirp->d_name); closedir(dp); exit(0);}说明: 实现简单的ls命令,与标准ls不同的是,此程序列出的目录中的文件名不是以字母顺序列出的。包含了dirent.h,调用其中的opendir和readdir函数,以及dirent结构体。opendir函数返回指向DIR结构的指针,在循环中调用readdir读取每个目录项,返回指向dirent的指针,当目录中没有目录项可读时,返回null。程序结束时,调用exit(0)。0表示正常退出,1~255表示出错。

June 18, 2020 · 1 min · jiezi

linux中的变量

变量的命名规则等号左右不能留空格变量的值如果含有空格需要使用双引号括起来变量命名推荐使用英文字母不要使用特殊字符变量的值中如果包含特殊字符需要使用转义字符 常见的环境变量PATH(环境变量问题)LANG(乱码问题的解决方案) 自定义变量将自定义变量转换成环境变量 export为什么需要将自定义变量转换成环境变量如何将自定义变量转换成环境变量 将环境变量转换成自定义变量 declare为什么需要将环境变量转换成自定义变量 变量声明 declare任何一门编程语言必定存在变量,变量必定存在类型,比如字符串,数组,数字等。linux中也一样。将一个变量定义成环境变量其实就是将一个变量定义成全局变量。 declare -x 另外可以设定一个变量为只读变量。 declare -r 指定一个变量的类型是数组类型 declare -a指定一个变量的类型为整型 declare -i 如何将将环境变量转换成自定义变量 为什么使用了export就可以在子进程中访问父进程的环境变量。每启动一个进程,更为确切的说法是在父进程中启动一个子进程,操作系统就会为这个子进程分配一块内存。同时子进程会将父进程的环境变量拷贝一份,所以在子进程中能够使用和父进程一样的环境变量。但是子进程并不拷贝父进程的自定义变量,因此子进程中无法访问到父进程的自定义变量。如果想访问到父进程的自定义变量,可以采用export将父进程的某些或者全部自定义变量,写进子进程的环境变量中。

October 2, 2019 · 1 min · jiezi

【Linux系统编程】普通用户绑定(bind)特权端口

有些知识不常使用真的容易忘啊,即使没有忘记,知识提取速度也够下午茶的。背景最近在学Haskell,今天用Haskell的Network.Socket模块实现了一个简单的基于TCP的daytime服务程序。程序运行阶段报了以下的错误:Network.Socket.bind: permission denied (Permission denied)我的第一反应怀疑是不是本地有服务程序占用端口号13,然后用命令netstat -tunl | grep 13查看,端口号并没有占用,所以第一种可能性不成立。是不是这个模块有类似的bug呢?但并没有查到。不放心,用C语言写了同样功能的程序,然后运行也会出错:bind error: Permission denied那是不是端口的问题,隐隐约约记得好像是小于1024的端口号不是预留给用户的。然后换了一个>=1024的端口,果然运行成功了。至此,思路才走上正轨。实际上小于1024的端口是特权端口,普通用户是没有权限绑定的。那如果我就是要用端口13呢,怎么解决呢?解决方案1.使用root权限运行最简单的方式就是登录root帐号,或者使用su切换到root。如果本机有配置sudo,普通用户也可使用该命令运行服务程序。2.使用setcap给服务程序赋予能力上一种方式是使用具有特权的用户,而该种方式是给程序赋予绑定特权端口的能力。操作如下:使用setcap ‘CAP_NET_BIND_SERVICE=+ep’ /path/to/program赋予(raise)绑定特权端口的能力使用setcap ‘CAP_NET_BIND_SERVICE=-ep’ /path/to/program清除(lower)绑定特权端口的能力也可使用setcap -r /path/to/program清除(remove)该程序的所有能力setcap简单使用说明除了CAP_NET_BIND_SERVICE,还有好多能力,可以参考capabilities(7)=、-是运算符,除此之外还有+;e和p是标记,除此之外还有i。可参考cap_from_text(3) Textual Representation一节的说明。setcap命令对内核有要求,必须>=2.6.24。 请关注我的公众号哦。

February 25, 2019 · 1 min · jiezi