文章目录
使用C程序访问环境变量
相关API函数
代码示例
文件输入重定向
代码示例
管道
无名管道
代码示例
小结
有名管道
代码示例
补充
信号
相关API函数
代码示例
信号的产生
mykill代码示例
使用C程序访问环境变量
系统提供了一个全局变量
extern char **environ;
使用全局变量environ将所有的环境变量输出。
相关API函数
getenv(3)
#include <stdlib.h> char *getenv(const char *name); 功能:获取环境变量的值 参数: name:环境变量的名字 返回值: NULL 没有找到这个环境变量 返回环境变量的值的首地址。
putenv(3)
#include <stdlib.h> int putenv(char *string); 功能:改变一个环境变量的值,或者增加一个环境变量 参数: string:name=value 返回值: 0 成功 非0 错误
clearenv(3)
#include <stdlib.h> int clearenv(void); 功能:清除环境变量 参数: void 返回值: 0 成功 非0 失败
setenv(3)
#include <stdlib.h> int setenv(const char *name,const char *value,int overwrite); 功能:改变或增加一个环境变量 参数: name:指定了环境变量的名字 value:指定了环境变量的值 overwrite: 0 环境变量存在,那么值不改变。 非0 环境变量存在,值被替换。 返回值: 0 成功 -1 失败 errno被设置
int unsetenv(const char *name);
功能:删除环境变量 参数: name:指定环境变量的名字 返回值: 0 成功 -1 失败 errno被设置
代码示例
- myenv.c
#include <stdio.h> int main(void){ extern char **environ; int i=0; while(*(environ+i)!=NULL){ printf("%s\n",*(environ+i)); i++; } return 0; }
- 执行结果
- myenv1.c
#include <stdio.h> int main(int argc,char *argv[],char *envp[]){ int i=0; for(;envp[i]!=NULL;i++){ printf("%s\n",envp[i]); } return 0; }
执行结果
- env_test.c
#include <stdio.h> #include <stdlib.h> int main(void){ printf("USER:%s\n",getenv("USER")); putenv("name=tarena"); printf("name:%s\n",getenv("name")); // putenv("name=pycoming"); setenv("name","pycoming",1); printf("name:%s\n",getenv("name")); unsetenv("name"); printf("name:%s\n",getenv("name")); clearenv(); printf("USER:%s\n",getenv("USER")); return 0; }
- 执行结果
文件输入重定向
代码示例
- upper.c
#include <stdio.h> #include <ctype.h> int main(void){ int ch; while((ch=getchar())!=EOF) putchar(toupper(ch)); return 0; }
- 执行结果
- wrap.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc,char *argv[]){ int fd; fd=open(argv[1],O_RDONLY); if(fd==-1){ perror("open"); return 1; } dup2(fd,STDIN_FILENO); close(fd); execl("./upper","upper",NULL); return 0; }
- 执行结果
管道
管道分为两种:有名管道、无名管道。
无名管道
无名管道的创建使用pipe
#include <unistd.h> int pipe(int pipefd[2]); 功能:创建管道 参数: pipefd[2]:管道的两个文件描述符。 pipefd[0] 读端 pipefd[1] 写端 返回值: 0 成功 -1 错误 errno被设置
代码示例
- pipe.c
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <string.h> #include <stdlib.h> int main(void){ pid_t pid; int fd[2]; char msg[]="this is a test\n"; char buf[128]; //创建管道 int r=pipe(fd); if(r==-1){ perror("pipe"); return 2; } //创建子进程 pid=fork(); if(pid==-1){ perror("fork"); return 1; } if(pid==0){//子进程的代码 close(fd[0]);//关闭读端 //向管道写内容 write(fd[1],msg,strlen(msg)); exit(0); }else{//父进程的代码 close(fd[1]);//管不写端 //从管道读取数据 int rt=read(fd[0],buf,128); write(1,buf,rt); //回收子进程的资源 wait(NULL); } return 0; }
- 执行结果
小结
1、父进程创建管道
2、fork(2)创建子进程
3、父进程关闭写端,子进程关闭读端
4、子进程写,父进程读
无名管道中需要使用到文件描述符,所以,无名管道应用于具有亲缘关系的进程间通信。
有名管道
有名管道的实质就是创建一个管道文件,一个进程向文件写数据,另一个进程从文件中读数据。创建有名管道需要使用mkfifo。
mkfifo(3)
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); 功能:创建一个有名的管道文件 参数: pathname:指定管道文件的名字 mode:指定了管道文件的权限 返回值: 0 成功 -1 错误 errno被设置
代码示例
- channelA.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <unistd.h> int main(int argc,char *argv[]){ char msg[]="hello world\n"; //创建管道文件 int m=mkfifo(argv[1],0664); if(m==-1){ perror("mkfifo"); return 1; } //打开管道文件 int fd=open(argv[1],O_RDWR); if(fd==-1){ perror("open"); return 2; } //向管道文件写入数据 sleep(20); write(fd,msg,strlen(msg)+1); //getchar(); close(fd); return 0; }
- channelB.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc,char *argv[]){ char buf[128]; //打开管道文件 int fd=open(argv[1],O_RDONLY); if(fd==-1){ perror("open"); return 1; } //从管道中读取数据 int r=read(fd,buf,128); write(1,buf,r); close(fd); return 0; }
执行结果
补充
带有环境变量的加载映像:
- execle.c
#include <stdio.h> #include <unistd.h> int main(void){ char *const ps_env[]={"name=tarena"\ ,NULL}; execle("./myenv","myenv",NULL,\ ps_env); return 0; }
- 执行结果
信号
信号就是软中断,软中断就是软件模拟的中断,中断是系统中的中断服务程序。
信号就是进程的异步通信机制,系统提供的信号可以通过 kill -l查看。
一般来说,信号有64个信号。
kill -信号编号 pid
进程对信号的默认处理动作就是终止当前进程。用户可以根据自己的需求来设置中进程对信号的处理。
SIG_DFL 缺省的 SIG_IGN 忽略 用户自定义信号处理函数
相关API函数
需要想进程注册一个函数,当信号来的时候,使用这个注册的信号处理函数来处理信号的到达。
signal(2)
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); 功能:为信号注册信号处理函数 参数: signum:信号的名字或者信号编号 handler: SIG_DFL 默认 SIG_IGN 忽略 用户自定义的信号处理函数 返回值: SIG_ERR 错误 返回原来的信号处理函数 举例验证,使用signal函数为进程注册信号处理函数。
代码示例
- signal.c
#include <stdio.h> #include <signal.h> //用户自定义的信号处理函数 void doit(int n){ printf("recv signal...\n"); return; } int main(void){ //进程对2号信号忽略 signal(2,SIG_IGN); //进程对3号信号处理,采用用户自定义的 signal(3,doit); while(1); return 0; }
- 执行结果
信号的产生
硬件产生信号
ctrl+c ctrl+\
使用linux命令发送信号
kill -信号编号 pid
使用函数给进程发送信号
kill(2)
#include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); 功能:发送信号给一个进程 参数: pid: 正数 进程的pid 给这个进程发送信号 sig: 指定信号编号 返回值: 0 成功 -1 错误 errno被设置
raise(3)
#include <signal.h> int raise(int sig); 功能:给当前进程发送信号 参数: sig:要发送的信号编号 返回值: 0 成功 非0 失败
alarm(2)
#include <unistd.h> unsigned int alarm(unsigned int seconds); 功能:设置一个传递信号的闹钟 参数: seconds: 设置闹钟的秒数 返回值: 保留的秒数
mykill代码示例
- mykill.c
#include <stdio.h> #include <sys/types.h> #include <signal.h> int main(int argc,char *argv[]){ //mykill 信号编号 pid int signum=atoi(argv[1]); pid_t pid=atoi(argv[2]); //给进程发送2号信号 kill(pid,signum); return 0; }
- 执行结果
- raise.c
#include <stdio.h> #include <signal.h> //参数n是信号的编号 void doit(int n){ printf("reav signum ...%d\n",n); return ; } int main(void){ printf("pid:%d\n",getpid()); signal(2,doit); while(1){ sleep(2); raise(2); } return 0; }
- 执行结果
- myalarm.c
#include <stdio.h> #include <unistd.h> int main(void){ int i; alarm(1); for(i=0;;i++) printf("%d\n",i); return 0; }
- 执行结果