程序分析

exec1.c & exect2.c & exect3.c

程序代码 (以exect1.c为例,其他两个结构类似)

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main()
  4. {
  5. char *arglist[3];
  6. arglist[0] = "ls";
  7. arglist[1] = "-l";
  8. arglist[2] = 0 ;//NULL
  9. printf("* * * About to exec ls -l\n");
  10. execvp( "ls" , arglist );
  11. printf("* * * ls is done. bye");
  12. return 0;
  13. }

运行结果:



结果显示代码“* * * ls is done. bye”没有打印出来。

原因:因为调用execvp,execlp,execv时,内核将新程序载入到当前进程,替代当前进程的代码和数据。

forkdemo1.c

程序代码:

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. int main()
  5. {
  6. int ret_from_fork, mypid;
  7. mypid = getpid();
  8. printf("Before: my pid is %d\n", mypid);
  9. ret_from_fork = fork();
  10. sleep(1);
  11. printf("After: my pid is %d, fork() said %d\n",
  12. getpid(), ret_from_fork);
  13. return 0;
  14. }

运行结果:

分析:fork()在父进程中返回子进程的pid,在子进程中返回0。

forkdemo2.c

程序代码:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main()
  4. {
  5. printf("before:my pid is %d\n", getpid() );
  6. fork();
  7. fork();
  8. printf("aftre:my pid is %d\n", getpid() );
  9. return 0;
  10. }

运行结果:

分析:两次fork()共产生3个子进程,加上父进程总共有4个进程。

forkdemo3.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. int main()
  5. {
  6. int fork_rv;
  7. printf("Before: my pid is %d\n", getpid());
  8. fork_rv = fork(); /* create new process */
  9. if ( fork_rv == -1 ) /* check for error */
  10. perror("fork");
  11. else if ( fork_rv == 0 ){
  12. printf("I am the child. my pid=%d\n", getpid());
  13. exit(0);
  14. }
  15. else{
  16. printf("I am the parent. my child is %d\n", fork_rv);
  17. exit(0);
  18. }
  19. return 0;
  20. }

运行效果:

forkdemo4.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. int main()
  5. {
  6. int fork_rv;
  7. printf("Before: my pid is %d\n", getpid());
  8. fork_rv = fork(); /* create new process */
  9. if ( fork_rv == -1 ) /* check for error */
  10. perror("fork");
  11. else if ( fork_rv == 0 ){
  12. printf("I am the child. my pid=%d\n", getpid());
  13. printf("parent pid= %d, my pid=%d\n", getppid(), getpid());
  14. exit(0);
  15. }
  16. else{
  17. printf("I am the parent. my child is %d\n", fork_rv);
  18. sleep(10);
  19. exit(0);
  20. }
  21. return 0;
  22. }

运行结果:

forkgdb.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. int gi=0;
  5. int main()
  6. {
  7. int li=0;
  8. static int si=0;
  9. int i=0;
  10. pid_t pid = fork();
  11. if(pid == -1){
  12. exit(-1);
  13. }
  14. else if(pid == 0){
  15. for(i=0; i<5; i++){
  16. printf("child li:%d\n", li++);
  17. sleep(1);
  18. printf("child gi:%d\n", gi++);
  19. printf("child si:%d\n", si++);
  20. }
  21. exit(0);
  22. }
  23. else{
  24. for(i=0; i<5; i++){
  25. printf("parent li:%d\n", li++);
  26. printf("parent gi:%d\n", gi++);
  27. sleep(1);
  28. printf("parent si:%d\n", si++);
  29. }
  30. exit(0);
  31. }
  32. return 0;
  33. }

运行效果:

分析:运行结果说明了子进程与父进程并发运行。

psh1.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #define MAXARGS 20
  6. #define ARGLEN 100
  7. //将字符串内容当做命令来执行。
  8. int execute( char *arglist[] )
  9. {
  10. execvp(arglist[0], arglist);
  11. perror("execvp failed");
  12. exit(1);
  13. }
  14. char * makestring( char *buf )
  15. {
  16. char *cp;
  17. buf[strlen(buf)-1] = '\0';
  18. cp = malloc( strlen(buf)+1 );
  19. if ( cp == NULL ){
  20. fprintf(stderr,"no memory\n");
  21. exit(1);
  22. }
  23. strcpy(cp, buf);
  24. return cp;
  25. }
  26. int main()
  27. {
  28. char *arglist[MAXARGS+1];
  29. int numargs;
  30. char argbuf[ARGLEN];
  31. numargs = 0;
  32. while ( numargs < MAXARGS )
  33. {
  34. printf("Arg[%d]? ", numargs);
  35. if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
  36. arglist[numargs++] = makestring(argbuf);
  37. else
  38. {
  39. if ( numargs > 0 ){
  40. arglist[numargs]=NULL;
  41. execute( arglist ); //将arglist中的字符串当做命令来执行。
  42. numargs = 0;
  43. }
  44. }
  45. }
  46. return 0;
  47. }

运行结果:

程序功能:输入字符串并将其当做命令执行。

psh2.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/wait.h>
  6. #include <unistd.h>
  7. #include <signal.h>
  8. #define MAXARGS 20
  9. #define ARGLEN 100
  10. char *makestring( char *buf )
  11. {
  12. char *cp;
  13. buf[strlen(buf)-1] = '\0';
  14. cp = malloc( strlen(buf)+1 );
  15. if ( cp == NULL ){
  16. fprintf(stderr,"no memory\n");
  17. exit(1);
  18. }
  19. strcpy(cp, buf);
  20. return cp;
  21. }
  22. void execute( char *arglist[] )
  23. {
  24. int pid,exitstatus;
  25. pid = fork();
  26. switch( pid ){
  27. case -1:
  28. perror("fork failed");
  29. exit(1);
  30. case 0:
  31. execvp(arglist[0], arglist);
  32. perror("execvp failed");
  33. exit(1);
  34. default:
  35. while( wait(&exitstatus) != pid )
  36. ;
  37. printf("child exited with status %d,%d\n",
  38. exitstatus>>8, exitstatus&0377);
  39. }
  40. }
  41. int main()
  42. {
  43. char *arglist[MAXARGS+1];
  44. int numargs;
  45. char argbuf[ARGLEN];
  46. numargs = 0;
  47. while ( numargs < MAXARGS )
  48. {
  49. printf("Arg[%d]? ", numargs);
  50. if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
  51. arglist[numargs++] = makestring(argbuf);
  52. else
  53. {
  54. if ( numargs > 0 ){
  55. arglist[numargs]=NULL;
  56. execute( arglist );
  57. numargs = 0;
  58. }
  59. }
  60. }
  61. return 0;
  62. }

运行结果:

程序功能:不断产生新的子进程输入字符串命令。

testbuf1

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. printf("hello");
  6. fflush(stdout);
  7. while(1);
  8. }

运行效果:

testbuf2

程序代码:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. printf("hello\n");
  5. while(1);
  6. }

运行效果:

testbuf3

程序代码:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. fprintf(stdout, "1234", 5);
  5. fprintf(stderr, "abcd", 4);
  6. }

运行效果:

分析:在默认情况下,stdout是行缓冲的,他的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕。而stderr是无缓冲的,会直接输出。所以输出结果为:abcd1234

testpid.c

程序代码:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/types.h>
  4. int main()
  5. {
  6. printf("my pid: %d \n", getpid());//获取当前进程pid
  7. printf("my parent's pid: %d \n", getppid());//获取当前进程父进程pid
  8. return 0;
  9. }

运行效果:

testpp.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. char **pp;
  6. pp[0] = malloc(20);
  7. return 0;
  8. }

运行效果:

testsystem.c

程序代码:

  1. #include <stdlib.h>
  2. int main ( int argc, char *argv[] )
  3. {
  4. system(argv[1]);
  5. system(argv[2]);
  6. return EXIT_SUCCESS;
  7. }
  • system函数:

system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。 返回值 =-1:出现错误 =0:调用成功但是没有出现子进程 >0:成功退出的子进程的id 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。

运行效果:

waitdemo1.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/wait.h>
  5. #include <unistd.h>
  6. #define DELAY 4
  7. void child_code(int delay)
  8. {
  9. printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
  10. sleep(delay);
  11. printf("child done. about to exit\n");
  12. exit(17);
  13. }
  14. void parent_code(int childpid)
  15. {
  16. int wait_rv=0; /* return value from wait() */
  17. wait_rv = wait(NULL);//子进程成功结束返回子进程PID,没有子进程则返回-1。
  18. printf("done waiting for %d. Wait returned: %d\n",
  19. childpid, wait_rv);
  20. }
  21. int main()
  22. {
  23. int newpid;
  24. printf("before: mypid is %d\n", getpid());
  25. if ( (newpid = fork()) == -1 )
  26. perror("fork");
  27. else if ( newpid == 0 )
  28. child_code(DELAY);
  29. else
  30. parent_code(newpid);
  31. return 0;
  32. }

运行效果:

waitdemo2.c

程序代码:

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <unistd.h>

  1. #define DELAY 10
  2. void child_code(int delay)
  3. {
  4. printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
  5. sleep(delay);
  6. printf("child done. about to exit\n");
  7. exit(27);
  8. }
  9. void parent_code(int childpid)
  10. {
  11. int wait_rv;
  12. int child_status;
  13. int high_8, low_7, bit_7;
  14. wait_rv = wait(&child_status);
  15. printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv);
  16. high_8 = child_status >> 8; /* 1111 1111 0000 0000 */
  17. low_7 = child_status & 0x7F; /* 0000 0000 0111 1111 */
  18. bit_7 = child_status & 0x80; /* 0000 0000 1000 0000 */
  19. printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7);
  20. }
  21. int main()
  22. {
  23. int newpid;
  24. printf("before: mypid is %d\n", getpid());
  25. if ( (newpid = fork()) == -1 )
  26. perror("fork");
  27. else if ( newpid == 0 )
  28. child_code(DELAY);
  29. else
  30. parent_code(newpid);
  31. }

运行结果:

argtest.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "argv.h"
  4. int main(int argc, char *argv[]) {
  5. char delim[] = " \t";
  6. int i;
  7. char **myargv;
  8. int numtokens;
  9. if (argc != 2) {
  10. fprintf(stderr, "Usage: %s string\n", argv[0]);
  11. return 1;
  12. }
  13. if ((numtokens = makeargv(argv[1], delim, &myargv)) == -1) {
  14. fprintf(stderr, "Failed to construct an argument array for %s\n", argv[1]);
  15. return 1;
  16. }
  17. printf("The argument array contains:\n");
  18. for (i = 0; i < numtokens; i++)
  19. printf("%d:%s\n", i, myargv[i]);
  20. execvp(myargv[0], myargv);
  21. return 0;
  22. }

功能:将输入字符串当做系统命令执行。

运行结果:

environ.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(void)
  4. {
  5. printf("PATH=%s\n", getenv("PATH"));
  6. setenv("PATH", "hello", 1);
  7. printf("PATH=%s\n", getenv("PATH"));
  8. #if 0
  9. printf("PATH=%s\n", getenv("PATH"));
  10. setenv("PATH", "hellohello", 0);
  11. printf("PATH=%s\n", getenv("PATH"));
  12. printf("MY_VER=%s\n", getenv("MY_VER"));
  13. setenv("MY_VER", "1.1", 0);
  14. printf("MY_VER=%s\n", getenv("MY_VER"));
  15. #endif
  16. return 0;
  17. }

运行效果:

environvar.c

运行代码:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. extern char **environ;
  5. int i;
  6. for(i = 0; environ[i] != NULL; i++)
  7. printf("%s\n", environ[i]);
  8. return 0;
  9. }

功能:打印环境变量。

运行效果:

sigactdemo.c

程序代码:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <signal.h>
  4. #define INPUTLEN 100
  5. void inthandler();
  6. int main()
  7. {
  8. struct sigaction newhandler;
  9. sigset_t blocked;
  10. char x[INPUTLEN];
  11. newhandler.sa_handler = inthandler;//新的信号处理函数效果与signal()类似
  12. newhandler.sa_flags = SA_RESTART|SA_NODEFER
  13. |SA_RESETHAND;//设置信号处理相关操作
  14. sigemptyset(&blocked); //将blocked信号集初始化,并清空。
  15. sigaddset(&blocked, SIGQUIT);//将SIGQUIT信号加入参数blocked信号集。
  16. newhandler.sa_mask = blocked;//暂时将block信号阻塞
  17. if (sigaction(SIGINT, &newhandler, NULL) == -1)
  18. perror("sigaction");
  19. else
  20. while (1) {
  21. fgets(x, INPUTLEN, stdin);
  22. printf("input: %s", x);
  23. }
  24. return 0;
  25. }
  26. void inthandler(int s)
  27. {
  28. printf("Called with signal %d\n", s);
  29. sleep(s * 4);
  30. printf("done handling signal %d\n", s);
  31. }

sigation结构体:

  1. struct sigaction {
  2. void (*sa_handler)(int);
  3. void (*sa_sigaction)(int, siginfo_t *, void *);
  4. sigset_t sa_mask;
  5. int sa_flags;
  6. void (*sa_restorer)(void);
  7. }
  • sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
  • sa_mask 指定在信号处理程序执行过程中,哪些信号应当被阻塞。默认当前信号本身被阻塞。
  • sa_restorer 已过时,POSIX不支持它,不应再使用。
  • sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
  • sa_flags还可以设置其他标志:
    • SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
    • SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
    • SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号

运行效果:

sigactdemo2.c

  1. #include <unistd.h>
  2. #include <signal.h>
  3. #include <stdio.h>
  4. void sig_alrm( int signo )
  5. {
  6. /*do nothing*/
  7. }
  8. unsigned int mysleep(unsigned int nsecs)
  9. {
  10. struct sigaction newact, oldact;
  11. unsigned int unslept;
  12. newact.sa_handler = sig_alrm;//设置处理函数
  13. sigemptyset( &newact.sa_mask );//清空newact的阻塞信号集
  14. newact.sa_flags = 0;//设置信号处理的其它操作为空
  15. sigaction( SIGALRM, &newact, &oldact );//显式取消阻塞信号
  16. alarm( nsecs );//设置闹钟
  17. pause();
  18. unslept = alarm ( 0 );//取消闹钟,并返回剩余时间
  19. sigaction( SIGALRM, &oldact, NULL );
  20. return unslept;
  21. }
  22. int main( void )
  23. {
  24. while( 1 )
  25. {
  26. mysleep( 2 );
  27. printf( "Two seconds passed\n" );
  28. }
  29. return 0;
  30. }

运行效果:

sigdemo1.c

  1. #include <stdio.h>
  2. #include <signal.h>
  3. void f(int);
  4. int main()
  5. {
  6. int i;
  7. signal( SIGINT, f );//改变键盘ctril+C处理函数
  8. for(i=0; i<5; i++ ){
  9. printf("hello\n");
  10. sleep(2);
  11. }
  12. return 0;
  13. }
  14. void f(int signum)
  15. {
  16. printf("OUCH!\n");
  17. }

运行效果:

sigdemo2.c

  1. #include <stdio.h>
  2. #include <signal.h>
  3. main()
  4. {
  5. signal( SIGINT, SIG_IGN );//设置忽略Ctrl+C中断信号。
  6. printf("you can't stop me!\n");
  7. while( 1 )
  8. {
  9. sleep(1);
  10. printf("haha\n");
  11. }
  12. }

运行效果:

sigdemo3.c

程序代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <signal.h>
  4. #include <unistd.h>
  5. #define INPUTLEN 100
  6. int main(int argc, char *argv[])
  7. {
  8. void inthandler(int);
  9. void quithandler(int);
  10. char input[INPUTLEN];
  11. int nchars;
  12. signal(SIGINT, inthandler);//^C
  13. signal(SIGQUIT, quithandler);//^\
  14. do {
  15. printf("\nType a message\n");
  16. nchars = read(0, input, (INPUTLEN - 1));
  17. if (nchars == -1)
  18. perror("read returned an error");
  19. else {
  20. input[nchars] = '\0';
  21. printf("You typed: %s", input);
  22. }
  23. }
  24. while (strncmp(input, "quit", 4) != 0);
  25. return 0;
  26. }
  27. void inthandler(int s)
  28. {
  29. printf(" Received signal %d .. waiting\n", s);
  30. sleep(2);
  31. printf(" Leaving inthandler \n");
  32. }
  33. void quithandler(int s)
  34. {
  35. printf(" Received signal %d .. waiting\n", s);
  36. sleep(3);
  37. printf(" Leaving quithandler \n");
  38. }

运行效果:

listargs.c

程序代码

  1. #include <stdio.h>
  2. main( int ac, char *av[] )
  3. {
  4. int i;
  5. printf("Number of args: %d, Args are:\n", ac);//ac为传入参数的个数。
  6. for(i=0;i<ac;i++)
  7. printf("args[%d] %s\n", i, av[i]);
  8. fprintf(stderr,"This message is sent to stderr.\n");
  9. }

运行效果:



pipe.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #define oops(m,x) { perror(m); exit(x); }
  5. int main(int ac, char **av)
  6. {
  7. int thepipe[2],
  8. newfd,
  9. pid;
  10. //判断管道输入格式是否正确
  11. if ( ac != 3 ){
  12. fprintf(stderr, "usage: pipe cmd1 cmd2\n");
  13. exit(1);
  14. }
  15. //管道建立失败,输出错误信息
  16. if ( pipe( thepipe ) == -1 )
  17. oops("Cannot get a pipe", 1);
  18. //子进程创建失败,输出错误信息
  19. if ( (pid = fork()) == -1 )
  20. oops("Cannot fork", 2);
  21. if ( pid > 0 ){
  22. close(thepipe[1]);
  23. if ( dup2(thepipe[0], 0) == -1 )//将thepipe[0]重定向到标准输入
  24. oops("could not redirect stdin",3);
  25. close(thepipe[0]);
  26. execlp( av[2], av[2], NULL);//试着执行av[2]中的命令
  27. oops(av[2], 4);
  28. }
  29. close(thepipe[0]);
  30. if ( dup2(thepipe[1], 1) == -1 )//将thepipe[1]重定向到标准输出
  31. oops("could not redirect stdout", 4);
  32. close(thepipe[1]);
  33. execlp( av[1], av[1], NULL);//试着执行av[1]中的命令
  34. oops(av[1], 5);
  35. }
  • pipe():

    1. 头文件 #include<unistd.h>

    2. 定义函数: int pipe(int filedes[2]);

    3. 函数说明: pipe()会建立管道,并将文件描述词由参数filedes数组返回。

      filedes[0]为管道里的读取端

      filedes[1]则为管道的写入端。

    4. 返回值: 若成功则返回零,否则返回-1,错误原因存于errno中。

execlp():

从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了。

返回值:

如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。

运行效果:

pipedemo2.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #define CHILD_MESS "I want a cookie\n"
  6. #define PAR_MESS "testing..\n"
  7. #define oops(m,x) { perror(m); exit(x); }
  8. main()
  9. {
  10. int pipefd[2];
  11. int len;
  12. char buf[BUFSIZ];
  13. int read_len;
  14. if ( pipe( pipefd ) == -1 )
  15. oops("cannot get a pipe", 1);
  16. switch( fork() ){
  17. case -1:
  18. oops("cannot fork", 2);
  19. case 0:
  20. len = strlen(CHILD_MESS);
  21. while ( 1 ){
  22. if (write( pipefd[1], CHILD_MESS, len) != len )
  23. oops("write", 3);
  24. sleep(5);
  25. }
  26. default:
  27. len = strlen( PAR_MESS );
  28. while ( 1 ){
  29. if ( write( pipefd[1], PAR_MESS, len)!=len )
  30. oops("write", 4);
  31. sleep(1);
  32. read_len = read( pipefd[0], buf, BUFSIZ );
  33. if ( read_len <= 0 )
  34. break;
  35. write( 1 , buf, read_len );
  36. }
  37. }
  38. }

运行结果:

pipedemo.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. int main()
  6. {
  7. int len, i, apipe[2];
  8. char buf[BUFSIZ];
  9. if ( pipe ( apipe ) == -1 ){
  10. perror("could not make pipe");
  11. exit(1);
  12. }
  13. printf("Got a pipe! It is file descriptors: { %d %d }\n",
  14. apipe[0], apipe[1]);
  15. while ( fgets(buf, BUFSIZ, stdin) ){
  16. len = strlen( buf );
  17. if ( write( apipe[1], buf, len) != len ){
  18. perror("writing to pipe");
  19. break;
  20. }
  21. for ( i = 0 ; i<len ; i++ )
  22. buf[i] = 'X' ;
  23. len = read( apipe[0], buf, BUFSIZ ) ;
  24. if ( len == -1 ){
  25. perror("reading from pipe");
  26. break;
  27. }
  28. if ( write( 1 , buf, len ) != len ){ //将标准输入写到标准输出
  29. perror("writing to stdout");
  30. break;
  31. }
  32. }
  33. }

运行结果:


stdinerdir1.c

程序代码:

  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. int main()
  4. {
  5. int fd ;
  6. char line[100];
  7. fgets( line, 100, stdin ); printf("%s", line );
  8. fgets( line, 100, stdin ); printf("%s", line );
  9. fgets( line, 100, stdin ); printf("%s", line );
  10. close(0);
  11. fd = open("/etc/passwd", O_RDONLY);//读取passwd文件到stdin
  12. if ( fd != 0 ){
  13. fprintf(stderr,"Could not open data as fd 0\n");
  14. exit(1);
  15. }
  16. fgets( line, 100, stdin ); printf("%s", line );
  17. fgets( line, 100, stdin ); printf("%s", line );
  18. fgets( line, 100, stdin ); printf("%s", line );
  19. }

stdinredir2.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>
  4. //#define CLOSE_DUP
  5. //#define USE_DUP2
  6. main()
  7. {
  8. int fd ;
  9. int newfd;
  10. char line[100];
  11. fgets( line, 100, stdin ); printf("%s", line );
  12. fgets( line, 100, stdin ); printf("%s", line );
  13. fgets( line, 100, stdin ); printf("%s", line );
  14. fd = open("data", O_RDONLY);
  15. #ifdef CLOSE_DUP
  16. close(0);
  17. newfd = dup(fd);
  18. #else
  19. newfd = dup2(fd,0); //将fd重定向到标准输入
  20. #endif
  21. if ( newfd != 0 ){
  22. fprintf(stderr,"Could not duplicate fd to 0\n");
  23. exit(1);
  24. }
  25. close(fd);
  26. fgets( line, 100, stdin ); printf("%s", line );
  27. fgets( line, 100, stdin ); printf("%s", line );
  28. fgets( line, 100, stdin ); printf("%s", line );
  29. }

运行效果:(没有data文件,无法获取文件描述符,重定向失败)

testtty.c

  1. #include <unistd.h>
  2. int main()
  3. {
  4. char *buf = "abcde\n";
  5. write(0, buf, 6);//将字符串写到标准输入
  6. }

运行效果:

whotofile.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. int main()
  5. {
  6. int pid ;
  7. int fd;
  8. printf("About to run who into a file\n");
  9. if( (pid = fork() ) == -1 ){
  10. perror("fork"); exit(1);
  11. }
  12. if ( pid == 0 ){
  13. close(1); /* close, */
  14. fd = creat( "userlist", 0644 ); /* then open *///以写的方式创建一个文件,因为前面关闭了文件描述符1,所以fd=1,为标准输出。
  15. execlp( "who", "who", NULL ); /* and run *///执行who命令,输出到文件表描述符1中。
  16. perror("execlp");
  17. exit(1);
  18. }
  19. if ( pid != 0 ){
  20. wait(NULL);
  21. printf("Done running who. results in userlist\n");
  22. }
  23. return 0;
  24. }

运行结果:

consumer.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <fcntl.h>
  5. #include <limits.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #define FIFO_NAME "/tmp/myfifo"
  9. #define BUFFER_SIZE PIPE_BUF
  10. int main()
  11. {
  12. int pipe_fd;
  13. int res;
  14. int open_mode = O_RDONLY;
  15. char buffer[BUFFER_SIZE + 1];
  16. int bytes = 0;
  17. memset(buffer, 0, sizeof(buffer));//数组置零
  18. printf("Process %d opeining FIFO O_RDONLY \n", getpid());
  19. pipe_fd = open(FIFO_NAME, open_mode);
  20. printf("Process %d result %d\n", getpid(), pipe_fd);
  21. if (pipe_fd != -1) {
  22. do {
  23. res = read(pipe_fd, buffer, BUFFER_SIZE);
  24. bytes += res;
  25. } while (res > 0);
  26. close(pipe_fd);
  27. } else {
  28. exit(EXIT_FAILURE);
  29. }
  30. printf("Process %d finished, %d bytes read\n", getpid(), bytes);
  31. exit(EXIT_SUCCESS);
  32. }

运行效果:

文件不存在,打开失败。

文件存在读取成功。

producer.c

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <fcntl.h>
  5. #include <limits.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #define FIFO_NAME "/tmp/myfifo"
  9. #define BUFFER_SIZE PIPE_BUF
  10. #define TEN_MEG (1024 * 1024 * 10)
  11. int main()
  12. {
  13. int pipe_fd;
  14. int res;
  15. int open_mode = O_WRONLY;
  16. int bytes = 0;
  17. char buffer[BUFFER_SIZE + 1];
  18. //判断文件是否存在。
  19. if (access(FIFO_NAME, F_OK) == -1) {
  20. res = mkfifo(FIFO_NAME, 0777);//创建一个FIFO文件
  21. if (res != 0) {
  22. fprintf(stderr, "Could not create fifo %s \n",
  23. FIFO_NAME);
  24. exit(EXIT_FAILURE);
  25. }
  26. }
  27. printf("Process %d opening FIFO O_WRONLY\n", getpid());
  28. pipe_fd = open(FIFO_NAME, open_mode);
  29. printf("Process %d result %d\n", getpid(), pipe_fd);
  30. if (pipe_fd != -1) {
  31. while (bytes < TEN_MEG) {
  32. res = write(pipe_fd, buffer, BUFFER_SIZE);
  33. if (res == -1) {
  34. fprintf(stderr, "Write error on pipe\n");
  35. exit(EXIT_FAILURE);
  36. }
  37. bytes += res;
  38. }
  39. close(pipe_fd);
  40. } else {
  41. exit(EXIT_FAILURE);
  42. }
  43. printf("Process %d finish\n", getpid());
  44. exit(EXIT_SUCCESS);
  45. }

access():

判断是否具有存取文件的权限

相关函数

stat,open,chmod,chown,setuid,setgid

表头文件

include<unistd.h>

定义函数

int access(const char * pathname, int mode);

函数说明

access()会检查是否可以读/写某一已存在的文件。参数mode有几种情况组合:

R_OK,W_OK,X_OK 和F_OK。

R_OK,W_OK与X_OK用来检查文件是否具有读取、写入和执行的权限。

F_OK则是用来判断该文件是否存在。由于access()只作权限的核查,并不理会文件形态或文件内容,因此,如果一目录表示为“可写入”,表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理。例如,你会发现DOS的文件都具有“可执行”权限,但用execve()执行时则会失败。

返回值

若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-1。

mkfifo()

mkfifo函数的作用是在文件系统中创建一个文件(该文件之前必须不存在),该文件用于提供FIFO功能,即命名管道。前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。

#include <sys/types.h>

  1. #include <sys/stat.h>
  2. int mkfifo( const char *pathname, mode_t mode );

mkfifo函数需要两个参数,第一个参数(pathname)是将要在文件系统中创建的一个专用文件。第二个参数(mode)用来规定FIFO的读写权限。Mkfifo函数如果调用成功的话,返回值为0;如果调用失败返回值为-1。

运行结果:

遇到的问题及解决

1.sigactdemo.c中的inthandler中的参数int s是怎么传进去的?

解决方法:在博客园提问。

inthandler被当做函数指针传给了newhandler.sa_handler

后面调用int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);

它的第一个参数signum指定的信号编号就是用来设置这个信号的处理函数的。信号SIGINT序号为2。

命令kill -l可以查看各信号的序号。

2.运行testpp时遇到段错误(核心已转储)。

解决方法:在博客园提问。

二维数组越界申请空间。

将代码改为

  1. pp=malloc(20);

即可编译成功。

参考资料

《深入理解计算机系统》第8章异常控制流

进程&信号&管道实践学习记录的更多相关文章

  1. PHP 中的多进程使用,进程通信、进程信号等详解

    多进程环境要求 Linux 系统 php-cli 模式 pcntl 扩展 或 swoole 扩展 pcntl 扩展 <?php $str = "hello world!" . ...

  2. linux 进程通信 管道

    1. 管道概述及相关API应用 1.1 管道相关的关键概念 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管 ...

  3. 进程信号的未决状态(pending status)

    这两天看了apue有关进程信号的部分,觉得未决状态这个词很是不一般,呵呵.一开始当我看到这个词,我不理解,什么意思呢,读了好几遍.不知道是书里面讲的晦涩难懂,还是脑子越来越不行了,就是没有搞明白.后来 ...

  4. Linux 两组信号对比(关闭和停止进程信号)

    之前看信号的时候,没有太注意不同信号的对比.今天再次看到的时候,突然感觉对一些信号,非常相似,乃至非常容易混淆.今天周末就抽空总结一下. 一.关闭进程信号 常见的4中关闭进程信号是SIGKILL,SI ...

  5. 【C】——sigprocmask 阻塞进程信号

    1.有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数.这种情况是通过阻塞信号实现的. 2.信号阻塞和忽略信号的区别. 阻塞的概念和忽略 ...

  6. 进程通信方式-管道pipe

    管道是两个进程间进行单向通信的机制.因为管道传递数据的单向性,管道又称之为半双工管道. 1.数据只能从一个进程流向另一个进程(其中一个写管道,另一个读管道):如果要进行全双工通信,需要建立两个管道. ...

  7. linux进程的管道通信

    linux进程的管道通信 要求 编程实现进程的管道通信,掌握管道通信的同步和互斥机制. 相关函数 pipe管道 指用于连接一个读进程和一个写进程以实现他们之间通信的一个共享文件,又名pipe文件.向管 ...

  8. Cobalt Strike系列教程第四章:文件/进程管理与键盘记录

    Cobalt Strike系列教程分享如约而至,新关注的小伙伴可以先回顾一下前面的内容: Cobalt Strike系列教程第一章:简介与安装 Cobalt Strike系列教程第二章:Beacon详 ...

  9. 进程-IPC 管道 (一)

    详见:https://github.com/ZhangzheBJUT/linux/blob/master/IPC(%E4%B8%80).md 一 IPC 概述 进程间通信就是在不同进程之间传播或交换信 ...

随机推荐

  1. MYSQL的慢查询两个方法

    对于排查问题找出性能瓶颈来说,最容易发现并解决的问题就是MYSQL的慢查询以及没有得用索引的查询. ================================================== ...

  2. log4net资料收集

    Log4net 日志使用介绍 http://www.cnblogs.com/jys509/p/4699813.html log4net Tutorial http://www.codeproject. ...

  3. Effective Java 09 Always override hashCode when you override equals

    Failure to do so will result in a violation of the general contract for Object.hashCode, which will ...

  4. docker-3 基础命令

    创建镜像 创建镜像的方法有三种: 基于已有的容器创建 基于本地模板导入 基于dockerfile 基于已有的容器创建 主要使用docker commit 命令,命令格式: docker commit ...

  5. Java SWT 做计算器。

    java  --  swt  - -  计算器 环境搭建 安装java.eclipse.以及对应的swt插件. 开始工程 建立工程: 在java下建立一个在其他 —- WindowsBuilder — ...

  6. 用shell脚本批量修改文件后缀名

    早上本想将一些照片上传到相册中,但是由于所有照片的扩展名都是JPG而不是小写的jpg,因此造成了“格式不正确”而不能上传照片.此刻就产生了这样一个问题:使用shell脚本如何批量将所有文件的扩展名JP ...

  7. USACO section1.1 Broken Necklace

    /* ID: vincent63 LANG: C TASK: beads */ #include <stdio.h> #include<stdlib.h> #include&l ...

  8. Listview的点击事件

    上篇文章总结了如何自定义listview的显示内容,然而listview不能只是提供显示功能,还必须能够点击它显示一些东西: listView.setOnItemClickListener(new O ...

  9. CentOS安装Hypernetes相关问题解法

    1.手动编译hyper缺少libdevmapper.h git clone -b v2_02_103 https://git.fedorahosted.org/git/lvm2.git /usr/lo ...

  10. 最小生成树 kruskal hdu 5723 Abandoned country

    题目链接:hdu 5723 Abandoned country 题目大意:N个点,M条边:先构成一棵最小生成树,然后这个最小生成树上求任意两点之间的路径长度和,并求期望 /************** ...