1.IPC方式有:
*管道(包括无名管道和命名管道)
*消息队列
*信号量
*共享存储
*Socket
*Streams
Socket和Streams支持多机通信
1.半双工,只在父子进程之间,管道可以看成特殊文件用read write读写只存在于内存不生成文件。
2.原型
int pipe(int fd[2])
返回值:成功0,失败-1
管道建立成功生成2个文件描述符,fd[0]读,fd[1]写
3.用法举例
建立管道:pipe(fd),判断是否成功
创建子进程:fork,判断是否成功
在父子进程读写:父进程写,子进程读
父:close(fd[0]),write(fd[1],内容,个数)
子:close(fd[1]),read(fd[0],,)
注:写时要关闭读管道,读时要关闭写管道
读写方向一但固定就无法改变。
#include
#include
#include
#include
int main ()
{
pid_t pid;
int fd[2];
char a[10] = {
0};
if(pipe(fd) == -1)
{
perror("pipe");
exit(-1);
}
pid = fork();
if(pid < 0)
{
perror("fork");
exit(-1);
}
else if(pid == 0)
{
close(fd[1]);
read(fd[0],a,strlen("xiao wei"));
printf("%s\n",a);
}
else
{
close(fd[0]);
write(fd[1],"xiao wei",strlen("xiao wei"));
}
return 0;
}
1.半双工,可以无关进程之间,以特殊文件形式存在文件系统
2.原型
int mkfifo(const char* pathname,mode_t mode)
返回值:成功0 ,失败-1,可以用perror查看失败原因
参数:和open一样,文件路径名,0600(读写)
参数1:可设置是否阻塞O_NONBLOCK,默认是阻塞。
3.例:
*进程1
open打开管道
read阻塞等待write(要用while)
输出读的数据
close关闭管道
*进程2
open打开管道
write写数据
close关闭管道
注:管道文件数据读后立马清空,先进先出
/*读代码*/
#include
#include
#include
#include
#include
#include
#include
#include
int main ()
{
int cnt = 3;
int fd;
char a[14] = {
0};
if(mkfifo("./fifo",0600) == -1 && errno != EEXIST)
{
perror("pipe");
exit(-1);
}
fd = open("./fifo",O_RDONLY);
if(fd == -1)
{
perror("open");
}
while(cnt)
{
read(fd,a,strlen(a));
printf("read:%s\n",a);
cnt--;
}
close(fd);
return 0;
}
/*写代码*/
int main ()
{
int cnt = 3;
int fd;
char *a = "xiao wei ...";
fd = open("./fifo",O_WRONLY);
if(fd == -1)
{
perror("open");
exit(-1);
}
while(cnt)
{
write(fd,a,strlen(a));
sleep(3);
cnt--;
}
close(fd);
return 0;
}
/*运行结果*/
/*
读进程那边输出:
read:xiao wei ...
read:xiao wei ...
read:xiao wei ...
写进程没3秒发数据一次,发3次后退出程序
*/
全双工,链表在内核中有标识符(队列ID),随机查询按类型读取,进程终止内容不会删除
int msgget(key_t key,int flag)
创建消息队列,成功返回0,失败-1
参数1:key可以用ftok函数,也可以直接写0x1234
参数2:创建队列IPC_CREAT,打开方式可读可写可执行0777
int msgsnd(int msqid,const void*ptr,size_t size,int flag)
添加消息,成功0失败-1
参数1:队列号key
参数2:结构体指针
struct msgbuf
{
long mtype;
char mtext[1];
}
参数3:个数用strlen算
参数4:0阻塞
int msgrcv(int msqid,void*ptr,size_t size,long type,int flag)
读取消息,成功返回数据长度
参数1:队列号
参数2:结构体指针
参数3:个数
参数4:消息类型,结构体的mtype
参数5:0阻塞等待
int msgctl(int msqid,int cmd,struct msqid_ds*buf)
控制消息队列,释放移除队列
参数1:队列号
参数2:常用IPC_RMID,释放移除队列
参数3:通常NULL
key_t ftok(const char*fname,int id)
返回值:key,队列号
参数1:当前目录
参数2:id
例:key=ftok(".",‘a’)
创建结构体
创建队列
接受消息,发送消息
移除队列
/*读代码*/
#include
#include
#include
#include
#include
#include
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
struct msgbuf readbuf;
memset(&readbuf,0,sizeof(struct msgbuf));
key_t key;
key = ftok(".",'z');
int msgid = msgget(key,IPC_CREAT|0777);
if(msgid == -1)
{
printf("get que failuer\n");
}
msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),666,0);
printf("readbuf:%s\n",readbuf.mtext);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
/*写代码*/
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
struct msgbuf writebuf = {
666,"xiao wei..."};
key_t key;
key = ftok(".",'z');
int msgid = msgget(key,IPC_CREAT|0777);
if(msgid == -1)
{
printf("get que failuer\n");
}
msgsnd(msgid,&writebuf,strlen(writebuf.mtext),0);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
/*运行结果*/
/*
先运行读
在运行写
读端输出
readbuf:xiao wei...
后结束程序
*/
1.共用一个内存,写读用指针指向这个内存
一读一写,前面内容销毁
2.API
int shmget(key_t key,size_t size,int flag)
创建打开一个共享内存
返回值:成功返回id,失败返回-1
参数1:key,用ftok
参数2:创建内存大小,必须以m为单位
参数3:创建共享内存IPC_CREAT,可读写0666
例:shmip=shmget(key,1024*4,IPC_CREAT|0666)
void *shmat(int shm_id,const void* addr,int flag)
连接共享内存地址空间
返回值:成功返回地址,失败-1
参数1:共享内存id
参数2:0
参数3:0
注:这个指针不需要free释放
int shmdt(void* addr)
断开连接
返回值:成功0失败-1
参数:id
int shmctl(int shm_id,int cmd,struct shmid_ds* buf)
控制共享内存,释放
返回值:成功0失败-1
参数1:id
参数2:IPC_RMID
参数3:0
3.例:
创建打开共享内存
连接映射共享内存
读写数据(用printf)
断开连接
释放干掉共享内存
//写
#include
#include
#include
#include
#include
#include
#include
int main()
{
int shm_id;
char *shmatadd;
key_t key;
key = ftok(".",'a');
shm_id = shmget(key,1024*4,IPC_CREAT|0666);
if(shm_id == -1){
printf("found fail\n");
exit(-1);
}
shmatadd = shmat(shm_id,0,0);
printf("shmat ok\n");
strcpy(shmatadd,"xiaowei");
sleep(3);
shmdt(shmatadd);
shmctl(shm_id,IPC_RMID,0);
return 0;
}
//读
int main()
{
int shm_id;
char *shmatadd;
key_t key;
key = ftok(".",'a');
shm_id = shmget(key,1024*4,0);
if(shm_id == -1){
printf("found fail\n");
exit(-1);
}
shmatadd = shmat(shm_id,0,0);
printf("shmat ok\n");
printf("data:%s\n",shmatadd);
shmdt(shmatadd);
printf("quit\n");
return 0;
}
/*判断共享内存内容,是否和上次内容一样
不一样做什么*/
if(strcmp(cmd1,shmatadd)){
strcpy(cmd1,shmatadd);
printf("cmd=%s\n",cmd1);
}
/*
strcpy(cmd,shmatadd);
if(strcmp(cmd,cmd1)){
strcpy(cmd1,cmd);
printf("cmd1= %s\n",cmd1);
}
*/
if((strcmp(cmd1,"quit") == 0) || (a == 60)){
printf("quit\n");
break;
}
一、一些命令
1.用指令kill -l,查看信号名称和编号
2.忽略,捕捉,系统默认信号
3.使用
例:杀死进程
kill -信号编号 进程pid
二、信号注册,捕捉,忽略(入门)
1.API
函数:
tpyedef void(*sighandler_t)(int)
函数指针
sighandler_t signal(int signum,sighandler_t handler)
参数1:信号名称
参数2:函数指针
高级:sigaction()
2.用signal捕捉信号,然后用函数指针更改系统默认信号,改成自己要操作的内容。
例:
捕捉信号
进入函数指针里,操作要干什么
注:9 SIGKILL,系统信号改变不了
#include
#include
#include
void handler(int signum)
{
printf("get signum:%d\n",signum);
switch(signum){
case 2:
printf("SIGINI\n");
break;
case 9:
printf("SIGKILL\n");
break;
case 10:
printf("SIGUSR1\n");
break;
}
printf("never quit\n");
}
int main()
{
signal(SIGINT,handler);
signal(SIGKILL,handler);
signal(SIGUSR1,handler);
while(1);
}
/*
用kill -9 进程pid,杀死进程
用kill-2 pid ,输出SIGINI(还可以用CTRL+c)
用kill -10 pid 输出SIGUSR1
*/
3.用函数main传参杀死进程
*API
int kill(pid_t pid,int sig)
发信号,杀死进程
参数:1.进程pid,2.信号编号加-
atoi()//char转int
参数:二级指针,mian形参
sprintf()
做字符串
参数:比printf前面多一个参数,char是指针型,做出来的字符串放到char*里面
*例:
main完整有形参
把2个字符型形参用atoi转整型(pid,signum)
2种方法
用kill杀死进程
用sprintf做字符串,在用system杀死进程
#include
#include
#include
int main(int argc,char **argv)
{
int signum;
int pid;
char cmd[128] = {
0};
signum = atoi(argv[1]);
pid = atol(argv[2]);
sprintf(cmd,"kill %d %d",signum,pid);
system(cmd);
printf("send signal ok\n");
return 0;
}
//使用:./a -9 2313
4.忽略信号
signal第二个参数写宏,SIG_ICN
注:忽略不了信号9
三、信号携带信息,收发(高级)
1.sigaction(捕捉信号)
参数1:信号编号
★参数2:结构体指针
参数3:备份,NULL
一般用法:都配置
2.struct sigaction
成员1:和signal的函数指针一样
★成员2:多个形参的函数指针
成员3:是否阻塞,默认阻塞
成员4:SA_SIGINFO
成员5:一般不用
一般用法:配成员2,4
3.函数指针handler()
参数1:int signum接受到的信号类型编号
参数2:结构体siginfo_t,读数据:si_int,pid,发消息:一个联合体,可以发整型和字符。
参数3:void*context指针,判断是否有数据传过来,无数据指向空NULL
例:
sigaction函数
配置结构体2个成员
写handler函数
函数里判断有数据打印数据
发送
1.sigqueue
参数1:给谁发pid
参数2:发什么信号
参数3:数据,联合体union sigval(整型,字符)
例:
用完整main,2个参数转int
函数sigqueue
写数据联合体(特别注意段错误,共用一个内存,写字符的时候要用指针)
#include
#include
#include
void handler(int signum, siginfo_t *info, void *context)
{
printf("get signum %d\n",signum);
if(context != NULL){
printf("get data:%d\n",info->si_int);
printf("get data:%d\n",info->si_value.sival_int);
printf("from:%d\n",info->si_pid);
}
}
int main()
{
struct sigaction buf;
buf.sa_sigaction = handler;
buf.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1,&buf,NULL);
while(1);
return 0;
}
/*输出
get signum 10
get data:10
get data:10
from:48116
*/
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
int signum;
int pid;
union sigval value;
value.sival_int = 10;
signum = atoi(argv[1]);
pid = atol(argv[2]);
sigqueue(pid,signum,value);
printf("%ddone\n",getpid());
return 0;
}
1.控制谁先运行
2.API
int semget(key_t key,int num_sems,int sem_flags)
创建,获取信号组
返回值:semid
参数:key,用flok
参数:信号组个数,一般
参数:IPC_CREAT|0666
int semop(int semid,struct sembuf *sops,size_t numops)
操作信号量,改变值
参数1:id
参数2:结构体指针可以有多个也可以是一个,
成员:sem_num,信号量编号0
成员:sem_op,操作信号量,-1,1
成员:sem_flg,SEM_UNDO
参数3:几个信号量
int semctl(int semid,int sem_num,int cmd,...)
控制信号量组相关信息
参数:id
参数:操作第几个信号量,0开始
参数:很多宏,常用SETVAL设置信号量值
IPC_RMID销毁
参数:联合体,union semun,开头要定义
初始化设置信号量值为1,联合体val=1
例:
创建信号量组
初始化信号量
创建父子进程
写2个函数,一个信号量加,一个减
子进程运行完信号量加
父进程先减然后运行在加
销毁锁
#include
#include
#include
#include
#include
#include
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
void pGetKey(int id)
{
struct sembuf set;
set.sem_num = 0;
set.sem_op = -1;
set.sem_flg = SEM_UNDO;
semop(id,&set,1);
printf("getkey\n");
}
void vPutBackKey(int id)
{
struct sembuf set;
set.sem_num = 0;
set.sem_op = 1;
set.sem_flg = SEM_UNDO;
semop(id,&set,1);
printf("put back the key\n");
}
int main()
{
key_t key;
int sem_id;
key = ftok(".",'a');
union semun initsem;
initsem.val = 0;//锁初始没有钥匙
sem_id = semget(key,1,IPC_CREAT|0666);
semctl(sem_id,0,SETVAL,initsem);
int pid = fork();
if(pid > 0){
pGetKey(sem_id);//父进程那不到,因为没有钥匙
printf("this is father\n");
vPutBackKey(sem_id);
}else if(pid == 0){
printf("this is child\n");
vPutBackKey(sem_id);//子进程执行完,放钥匙进去
}else
{
printf("fork error\n");
exit(-1);
}
semctl(sem_id,0,IPC_RMID);
return 0;
}