Linux网络应用开发---C程序调用系统命令和shell

1.作用和背景:

为了使Linux应用开发工作更有效率,我们可以在C程序中通过调用linux系统命令或编写的shell脚本,并把执行的结果返回给C程序,从而来大大提高开发效率。

例如:

1)我们需要应用程序中获取系统内存的总大小和当前内存的使用情况,使用free命令很容易实现;

2)再如要获取网络与服务器的连通情况,可使用以ping命令也非常容易实现;

上述两个例子中的功能,如果要使用C程序的源码来实现,最少可能需要上百行的代码。

使用场景总结起来有如下几个方向(以下均以system函数为例):

1)在C语言程序中调用系统命令,如:system("df-h")或system("");

2)在C语言程序中调用自定义的shell脚本,如:system("/home/");或system("cat/etc/passwd");

3)在C语言程序中调用其它应用进程,如:system("/usr/bin/");system("./test123");

2.详细介绍:

Linux应用C程序调用系统命令或shell脚本共有三个函数可以实现:system,exec系列函数和popen函数。

1)system函数:

---函数定义:intsystem(constchar*string);

---函数说明:

()会调用fork()产生子进程,由子进程来调用/bin/sh-cstring来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程;

b.在调用system()期间SIGCHLD信号会被暂时搁置,SIGINT和SIGQUIT信号则会被忽略;

c.返回值如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1;

d.若参数string为空指针(NULL),则返回非零值;

e.如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为system()调用/bin/sh失败所返回的127,因此最好能再检查errno来确认执行成功;

f.附加说明在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境变量可能会造成系统安全的问题;

---实现原理:

system是一个阻塞的函数,实际上是创建了一个新的进程开始运行,并等待执行完成后返回;相当于先后调用了fork,exec,wait来执行外部命令;

另外system不会返回执行的结果,只是会返回执行是否成功;在执行过程中会自动对进程进行管理,无需我们理会;

---例子程序:

查看目录和文件信息

system("ls-lt");

设置网卡IP为192.168.1.100

system("");

运行播放器程序:

system("/usr/bin/");

2)exec系列函数:

exec其实并不是一个函数,而是由六个以exec开头的函数所构成的一个函数族,

---函数定义:

intexecl(constchar*path,constchar*arg,);

intexeclp(constchar*file,constchar*arg,);

intexecle(constchar*path,constchar*arg,,char*constenvp[]);

intexecv(constchar*path,char*constargv[]);

intexecvp(constchar*file,char*constargv[]);

intexecvpe(constchar*file,char*constargv[],char*constenvp[]);

---函数说明:

-path:可执行文件的路径名字

-arg:可执行程序所带的参数列表,第一个参数为可执行文件名字,后面是是一个参数列表,它表示需要的命令行参数,且必须以NULL结束;

-file:如果参数file中包含/,则就将其视为路径名,否则就按PATH环境变量,在它所指定的各目录中搜寻

可执行文件。

-argv:可执行的参数数组;

-返回值:exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点

接着往下执行。

总结:

l:使用参数列表;

p:使用文件名,并从PATH环境进行寻找可执行文件;

v:使用参数数组,然后将该数组的地址作为这些函数的参数;

e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量;

---实现原理:

a.其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数;

函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件;

c.对于exec系列函数一个进程一旦调用exec类函数,它本身就“死亡”了,用它来取代原调用进程的数据段、代码段和堆栈段,

在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换;

类函数中有的还允许继承环境变量之类的信息,这个通过exec系列函数中的一部分函数的参数可以得到。

e.这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件;

---例子说明:

(1)execl例子:

(intargc,charargv**){printf("==Thisisexeclfunctiontest.\n");execl("/bin/ls","ls","-a","-l",NULL);//参数是一个调用函数的参数列表,且必须以NULL结束;return0;}

(2)execlp例子:

1.execl函数后面加一个p表示使用文件名,并从PATH环境进行寻找可执行文件,

2.带p的函数包括execlp、execvp、execvpe,如果参数file中包含/,则就将其视为路径名,否则就

3.按PATH环境变量,在它所指定的各目录中搜寻可执行文件。举个例子,PATH=/bin:/usr/bin

(intargc,char**argv){printf("beforeexecl!\n");if(execlp("date","date",NULL,NULL)==-1){printf("execlfiled!\n");perror("becasue");}printf("Executeafterfailure!\n");return0;}

(3)execle例子:

调用参数是以列表方式给出,即execle(path,arg1,arg2,,envp),并且提供了环境变量参数列表envp

(intargc,char**argv){char*envp[]={"PATH=$PATH:/tmp/bin","USER=Tom",NULL};char*argv[]={"ls","-l",NULL};if(fork()==0){if(execle("/bin/ls",argv,envp)0)perror("execleerror!");}return0;}

3)popen和pclose函数:

---函数定义

FILE*popen(constchar*command,constchar*type);//建立管道I/O,并返回创建的文件句柄,若成功返回文件指针,出错则返回NULL。

intpclose(FILE*stream);//关闭子进程创建的文件句柄;

---函数说明:

.cmd:是一个指向以NULL结束的shel1命令字符串的指针,这行命令将被传到bin/bash或sh并使用-c标志,shell将执行这个命令。

.type:可使用“r”或者"w",分别代表读取及写入,但由于popen是以创建管道的方式创建进程连接到子进程的标准输出设备或标准输入设备,因此其带有管道的一些特性,同一时刻只能定义为写或者读;

.返回值:如果调用fork0或pipe0失败,或者不能分配内存将返回NULL,否则返回标准I/0流。

.pclose:函数关闭标准1/0流,等待命令执行结束,然后返回shell的终止状态;如果shell不能被执行,则pclose0返回的终止状态与shell已执行exit一样。

---实现原理:

即采用在两进程间采用匿名管道的方式来进行通信,具体说明如下:

函数会创建一个管道,类似与pipe函数创建管道;再fork一个子进程,在子进程中执行execX函数来执行comm命令(因为execX执行新程序后新程序的进程空间会覆盖原进程的进程空间,所以开一个子进程来执行execX家族函数),然后返回stdout或者stdin的文件指针(取决于type);

b.由于command命令是通过子进程的执行的,那么stdin或者stdout文件指针也是子进程的进程片空间的,要将其返回给父进程,需要通过管道来实现;

是供程序写数据的,stdout是供程序读数据的。管道的读端跟stdout绑定,管道的写端跟stdin绑定;

d.读写管道操作无非就是管道(文件)的fd(文件描述符),这里将fd封装到文件流指针fp中;

e.通过这个管道执行标准输入输出操作,这个管道必须由pclose0函数关闭,而不是fcose函数(若使用fclose则会产生僵尸进程);

f.在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。

---例子程序:

/#includesys/_test(){printf("0==Thisis%sstarting\n",__FUNCTION__);intret=system("ls-la");printf("===%sret:%d.===\n",__FUNCTION__,ret);}staticvoidexecl_test(){pid_trepid=vfork();if(repid0){printf("%sforkerror\n",__FUNCTION__);return;}elseif(repid==0){printf("1==Thisis%sstarting\n",__FUNCTION__);intret=execl("/bin/ls","ls","-a","-l",NULL);printf("===%sret:%d.===\n",__FUNCTION__,ret);}else{wait(NULL);printf("[%s]----!\n",__FUNCTION__);}}staticvoidexeclp_test(){pid_trepid=fork();if(repid==0){printf("2==Thisis%sstarting\n",__FUNCTION__);intret=execlp("ls","ls","-a","-l",NULL);printf("===%sret:%d.===\n",__FUNCTION__,ret);}elseif(repid0){wait(NULL);printf("[%s]----!\n",__FUNCTION__);}}staticvoidexecle_test(){char*envp[]={"PATH=$PATH:/tmp/bin","USER=Tom",NULL};intret=0;pid_trepid=fork();if(repid==0){printf("3==Thisis%sstarting\n",__FUNCTION__);if((ret=execle("/bin/ls","ls","-l",NULL,envp))0)perror("execleerror!");printf("===%sret:%d.===\n",__FUNCTION__,ret);sleep(1);}elseif(repid0){wait(NULL);printf("[%s]----!\n",__FUNCTION__);}}staticvoidexecv_test(){char*argv[]={"ls","-l","-a",NULL};intret=0;pid_trepid=fork();if(repid==0){printf("4==Thisis%sstarting\n",__FUNCTION__);if((ret=execv("/bin/ls",argv))==-1){perror("becasue");}printf("===%sret:%d.===\n",__FUNCTION__,ret);sleep(1);}elseif(repid0){wait(NULL);printf("[%s]----!\n",__FUNCTION__);}}staticvoidexecvp_test(){printf("5==Thisis%sstarting\n",__FUNCTION__);char*argv[]={"ls","-l","-a",NULL};intret=0;pid_trepid=fork();if(repid==0){if((ret=execvp("ls",argv))==-1){perror("becasue");}printf("===%sret:%d.===\n",__FUNCTION__,ret);sleep(1);}elseif(repid0){wait(NULL);printf("[%s]----!\n",__FUNCTION__);}}staticvoidexecve_test(){char*envp[]={"PATH=$PATH:/tmp/bin","USER=Tom",NULL};char*argv[]={"ls","-l",NULL};pid_trepid=fork();if(repid==0){printf("6==Thisis%sstarting\n",__FUNCTION__);if(execve("/bin/ls",argv,envp)0)perror("execleerror!");printf("===%s!===\n",__FUNCTION__);sleep(1);}elseif(repid0){wait(NULL);printf("[%s]----!\n",__FUNCTION__);}}staticvoidpopen_test(){printf("7==Thisis%sstarting\n",__FUNCTION__);FILE*fp=popen("ls-l","r");if(fp==NULL){printf("Failedtoruncommand\n");exit(1);}charpath[1024]={0};intiCounter=0;while(fgets(path,sizeof(path),fp)!=NULL){iCounter++;printf("[%d]---%s",iCounter,path);memset(path,0,sizeof(path));}printf("[%s]----!\n",__FUNCTION__);pclose(fp);}/////////////////////////////////////maintest/////////////////////////intmain(intargc,char**argv){///0.systemfunctiontest;system_test();///1.execlfunctiontest;execl_test();///2.execlpfunctiontest;execlp_test();///3.execlefunctiontest;execle_test();///4.execvfunctiontest;execv_test();///5.execvpfunctiontest;execvp_test();///6.execvefunctiontest;execve_test();///7.popen/pclosefunctest;popen_test();}

版权声明:本站所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请举报,一经查实,本站将立刻删除。

相关推荐