linux基础——使用C程序访问环境变量及进程通信(管道)


使用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

    扫描二维码关注公众号,回复: 9495050 查看本文章
#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;
}
  • 执行结果
    在这里插入图片描述
发布了102 篇原创文章 · 获赞 27 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_37596943/article/details/104191717
今日推荐