程序通訊(命名管道,訊號集)
命名管道:(由於匿名管道(沒有名字,沒有路徑)通訊只能具有親緣關係的程序之間能,大大限制了程序間通訊的能力)
命名管道的特點:
1、可以使用不同程序(無論是否有親緣關係的程序)通訊
2、是一個特殊檔案:檔名與路徑(檔案系統中),是一個FIFO的檔案(沒有lssek)
3、普通在讀寫方面沒有阻塞,而FIFO檔案卻與普通不同在讀寫方面:
程序讀:
1、若該FIFO管道是阻塞
2、若該FIFO管道是非阻塞開啟,無論FIFO中是否有內容,都不會阻塞等待。
程序寫:
1、非阻塞
2、阻塞開啟檔案,如果讀程序不讀取完成,則寫程序一直等待
注:fifo預設是阻塞檔案。
API:建立一個管道檔案:
int mkfifo(const char *pathname, mode_t mode);
返回值:0成功 -1失敗 錯誤碼在errno中
pathname:路徑
mode:許可權
阻塞模式建立命名管道檔案 ./info 對管道檔案進行寫入資料 .
#include<iostream>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
//系統錯誤
#include<errno.h>
using namespace std;
int main()//寫程序
{
//1第一步:建立管道named檔案
if(mkfifo("./info",0644)<0)
{
if(EEXIST!=errno)
{
perror("mkfifo fail");
return -1;
}
}
//1開啟寫入:以只讀和非阻塞開啟
int fd=open("./info",O_WRONLY);
//2操作
char msg[100]="I Love You!#Do you love me?";
cout<<write(fd,msg,strlen(msg))<<endl;
//3關閉
close(fd);
}
新建一個檔案 , 用於讀取命名管道里面的資料 ./info .
#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
using namespace std;
int main()
{
//開啟
int fd=open("./info",O_RDONLY);
if(fd<0)
{
perror("open fail\n");
return -1;
}
//讀取
char ch;
while(read(fd,&ch,1)>0)
{
if(ch=='#')
cout<<endl;
else
cout<<ch;
}
cout<<endl;
close(fd);
return 0;
}
非阻塞模式開啟檔案 O_NONBLOCK 方式開啟 .
#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
using namespace std;
int main()
{
//開啟
int fd=open("./info",O_RDONLY|O_NONBLOCK);
if(fd<0)
{
perror("open fail\n");
return -1;
}
//讀取
char ch;
while(read(fd,&ch,1)>0)
{
if(ch=='#')
cout<<endl;
else
cout<<ch;
}
cout<<endl;
close(fd);
return 0;
}
訊號:(system IPC:UNIX)是比較古老的程序間通訊的一種方法。主要是向另外一個程序發出通知。
1、訊號:系統給每一個訊號都取了一個編號:
shell: Kill -l
31號訊號之前代表不靠訊號
34訊號之後可靠(鏈式結構)
shell: man 7 signal (具體的說明)
1) SIGHUP 停止程序 終端退出時
2) SIGINT 停止程序 Ctrl+C組合鍵,發出
9) SIGKILL 停止程序 使用者退出程序
14) SIGALRM 時鐘鬧鐘
10) SIGUSER1 12)SIGUSER2 使用者自定義訊號
17) SIGCHLD 子程序退出,子程序傳送給資訊給父程序
訊號的處理方式:
1、系統預設處理SIG_DFL
2、使用者自處理
3、忽略;SIG_IGN
產生一個訊號:
1、硬體產生: ctrl+c 硬體產生一個訊號 結束
ctrl+/ 硬體產生一個訊號 結束(產生一個core檔案)
2、系統產生:
子程序退出,給父程序傳送訊號
3、使用者呼叫核心API來產生:
kill raise alarm pause
int kill(pid_t pid, int sig);
pid:程序的ID sig訊號標識
int raise(int sig);
unsigned int alarm(unsigned int seconds);
注:只允許定義一個鬧鐘,多個會被最新的替換
pause() 等待任意一個訊號到來就喚醒。
注:訊號處理是非同步方式
(同步與非同步)
處理資訊的步驟:
1、註冊:訊號+處理方式
2、訊號的產生
拓展:
前端程序:程序在終端上執行
後臺程序:脫離終端,在後參執行。 可執行檔案 &
訊號集 :
使用訊號集函式處理一組訊號,這些訊號按照呼叫的先後次序分為如下幾類:
1、建立訊號集:
2、登記訊號:決定程序如何處理訊號
3、訊號的處理與檢測:
建立訊號集
int sigemptyset(sigset_t *set);//清空訊號集
int sigfillset(sigset_t *set); //填滿
int sigaddset(sigset_t *set, int signum);//增加某個訊號
int sigdelset(sigset_t *set, int signum);//刪除某個訊號
int sigismember(const sigset_t *set, int signum);//查詢訊號是否在該訊號集中
建立訊號集 , signal(SIGINT,sigfun); ---->使用者自處理
signal(SIGINT,SIG_DFL); ---->系統預設處理
設定訊號集的功能:
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how:指定訊號集的的
set:訊號集
olds:把回之前的訊號集
指定訊號集的動作:
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
act:將程序的訊號集修改
old:返回修改前的訊號集
#include<iostream>
#include<signal.h>
using namespace std;
//訊號使用者自處理
void sigfun(int sig)
{
//使用者傳送SIGINT(Ctrl+C)
if(SIGINT==sig)
{
cout<<"使用者想幹掉我"<<endl;
}
}
int main()
{
//1註冊訊號: signal 使用者輸入CTRL+C 時,發出訊號
//signal(SIGINT,sigfun);//使用者自處理
//系統預設處理
//signal(SIGINT,SIG_DFL);
//系統收到此訊號,但要求忽略處理
signal(SIGINT,SIG_IGN);
while(1)
{
cout<<"I`m working"<<endl;
sleep(1);
}
return 0;
}
鬧鐘的訊號 .
#include<iostream>
#include<signal.h>
#include<stdlib.h>
using namespace std;
void sigfun(int sig)
{
if(sig==SIGALRM)
{
cout<<"鬧鐘響啦,休息一下"<<endl;
}
}
int main()
{
//1定義訊號
signal(SIGALRM,sigfun);
//定時: 10到了,會給本程序傳送一個SIGALRM的訊號
alarm(10);
alarm(2);
while(1)
{
cout<<"I`m working"<<endl;
sleep(1);
}
}
鬧鐘訊號 .
#include<iostream>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>
using namespace std;
void sigfun(int sig)
{
if(SIGALRM==sig)
{
cout<<"鬧鐘響了"<<endl;
}
else if(SIGINT==sig)
{
cout<<"ctrl+c被按下"<<endl;
}
}
int main()
{
//註冊訊息
signal(SIGALRM,sigfun);
signal(SIGINT,sigfun);//Ctrl+C
//定義一個鬧鐘
//alarm(5);//定義5秒
//阻塞等待訊號的到來
//pause();
sleep(100);
while(1)
{
cout<<"哈哈,我在玩..."<<endl;
sleep(1);
}
return 0;
}
訊號集的實現 .
#include<iostream>
#include<stdio.h>
#include<signal.h>
using namespace std;
void sigfun(int sig)
{
if(SIGINT==sig)
{
cout<<"如果你想退出程序,請按Ctrl+\\"<<endl;
}
}
//SIGQUIT SIGINT SIGALARM加入訊號集,然後設定為阻塞狀態,當該等待5秒之後再恢復
int main()
{
signal(SIGINT,sigfun);
//1建立一個訊號集(替換程序的集號)
sigset_t set;
if(-1==sigemptyset(&set))//1先清空(set是隨機值,可能包含其他訊號)
{
perror("clear fail");
return -1;
}
//1.1新增上述兩個訊號到訊號集中
if(sigaddset(&set,SIGQUIT)<0)
{
perror("add fail");
return -1;
}
if(sigaddset(&set,SIGINT)<0)
{
perror("add fail");
return -1;
}
sigset_t oldset;
//2.決定訊號集的處理---阻塞模式
if(sigprocmask(SIG_BLOCK,&set,&oldset)<0)
{
perror("procmask fail");
return -1;
}
//睡眠10s
sleep(10);
cout<<"10休息完成"<<endl;
//恢復之前的狀態
if(sigismember(&oldset,SIGINT)==1)
{
cout<<"SIGINT在該訊號集中"<<endl;
}
else
cout<<"不在"<<endl;
sigprocmask(SIG_UNBLOCK,&set,NULL);
sleep(20);
return 0;
}