上篇中的無名管道通信是父子進程之間的通信,限定了進程之間的通信,從而就有了有名管道,它可以使不同進程之間進行通信,有名管道可以通過指定路徑名來指出,兵長文件系統中可見。進程通過文件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();
}
}