上篇中的无名管道通信是父子进程之间的通信,限定了进程之间的通信,从而就有了有名管道,它可以使不同进程之间进行通信,有名管道可以通过指定路径名来指出,兵长文件系统中可见。进程通过文件IO来操作有名管道,有名管道遵从先进先出的原则,但是不支持lseek函数。
1)int mkfifo(const char *pthname,mode_t mode)创建有名管道,
2)在内核中创建对象,但没有打开读写,有名管道的读写要自己打开,
3)文件对象在文件系统中创建文件节点,
4)在两个进程中,只会创建一次,若有节点则不会创建,第二次创建会返回错误信息,
FIFO的一般形式函数:
#include
#include
#include
#include
#include
#include
#include
/* open a read endpoint on a FIFO */ int fifo_read (const char *pathname); /* open a write endpoint on a FIFO */ int fifo_write(const char *pathname); /* print usage info */ void usage(const char *argv0); int main(int argc,char *argv[]) { if (argc < 3) { usage(argv[0]); return -1; } if ('r' == argv[1][0]) { if (fifo_read(argv[2]) < 0) { return -1; } } else if ('w' == argv[1][0]) { if (fifo_write(argv[2]) < 0) { return -1; } } else { usage(argv[0]); return -1; } return 0; } int fifo_read (const char *pathname) { int fd; /* * Ignore EEXIST for this case. * EEXIST means the FIFO has been created already. */ if (mkfifo(pathname, 0666) < 0) { if (EEXIST == errno) { printf("FIFO has been created at %s\n", pathname); } else { perror("mkfifo error"); return -1; } } else { printf("FIFO was created at %s\n", pathname); } if ((fd = open(pathname, O_RDONLY)) < 0) { perror("open for read w/ block error"); return -1; } printf("open read endpoint success.\n"); return 0; } int fifo_write(const char *pathname) { int fd; /* * Ignore EEXIST for this case. * EEXIST means the FIFO has been created already. */ if (mkfifo(pathname, 0666) < 0) { if (EEXIST == errno) { printf("FIFO has been created at %s\n", pathname); } else { perror("mkfifo error"); return -1; } } else { printf("FIFO was created at %s\n", pathname); } if ((fd = open(pathname, O_WRONLY)) < 0) { perror("open for write w/ block error"); return -1; } printf("open write endpoint success.\n"); return 0; } void usage(const char *argv0) { printf( "Usage : %s
\n" "
\n" " r: create read endpoint\n" " w: create write endpoint\n" "
:\n" " path to the FIFO file in filesystem.\n" , argv0); }
信号通信
1)信号通信是在软件层次上对中断机制的一种模拟,是一种异步通信方式。
信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件,
若果该进程当前处于未执行的状态,该信号就由内核保存起来,直到该进程恢复执行再传递给它,若果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到阻塞被取消才传递给进程。
2)信号的生命周期
4)信号在内核中的形式:
1 信号的发生pending
2 信号在进程中注册
3 信号的投递(执行和注销):执行信号的动作称为信号的投递
//
信号的未决:信号保存在内核中,直到信号被处理,返回给用户态处理
信号的阻塞block
信号的部署:就是处理信号的函数(可以自己制定)信号的处理函数在用户态进行处理,使用信号的阻塞,调用signal函数和pause函数,
内核信号的处理是在特定时间片才执行的(在内核进程退出的前夜统一处理多数信号,返回给用户进程处理过程叫投递)
信号的部署,就是通过系统特定的信号集,比如SIGINT/SIGQUIT/这些系统信号不被CTRL+C处理掉,但可以被KILL杀死
3)用户进程对信号的响应方式:
1 忽略信号:对信号不做任何处理,但是有两个信号不能忽略,就是SIGKILL和SIGSTOP,
2 捕捉信号:定义信号处理函数,当信号发生时,执行响应额处理函数,
3 执行缺省操作:Linux对每种信号都规定了默认操作。
3)信号的使用场合:
后台进程需要使用信号,例如xinetd
若果两个进程没有亲缘关系,无法使用无名管道
若果两个进程只有只能使用标准输入和标准输出,则不可以使用有名管道。
信号的部署函数的一般形式:
#include
#include
#include
#include
#include
#include
pid_t pid; void func1(int sign) { pid_t ppid = getppid(); if (sign == SIGINT) kill(ppid,SIGUSR1); if (sign == SIGQUIT) kill(ppid,SIGUSR2); if(sign == SIGUSR1){ printf("please get off the bus \n"); kill(ppid,SIGKILL); } exit(0); } void func2(int sign) { if (sign == SIGUSR1) printf("let is gogogo\n"); if (sign == SIGUSR2) printf("stop the bus \n"); if (sign == SIGTSTP) kill(pid,SIGUSR1); } int main () { printf("waiting for singal SIGINT or SIGQUIT\n"); pid = fork(); if (pid == -1){ perror("fork"); exit (-1); } if (pid > 0){ signal(SIGTSTP,func2); signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); signal(SIGUSR1,func2); signal(SIGUSR2,func2); pause(); } if (pid == 0){ signal(SIGINT,func1); signal(SIGQUIT,func1); signal(SIGTSTP,SIG_IGN); signal(SIGUSR1,func1); signal(SIGUSR2,SIG_IGN); pause(); } }