一.进程间通信概述
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。
IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC
二.管道
1.匿名管道
(1)特点
1.半双工,具有固定的写端和读端
2.只能用与具有亲缘关系的进程之间的通信(父子进程和兄弟进程之间)
3.可以看成一种特殊的文件,不属于其他任何文件系统,只存在于内存中
4.管道中的数据读走就没了
(2)API
int pipe(int pipefd[2])
返回值:成功返回0,失败返回-1
fd[0]:读端,为读而打开
fd[1]:写端,为写而打开
关闭管道:关闭读端和写端
使用write函数进行写入,使用read函数进行读出,使用close函数关闭
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd[2];
int pid;
char buf[128];
// int pipe(int pipefd[2]);
if(pipe(fd) == -1){
printf("creat pipe failed\n");
}
pid = fork();
if(pid<0){
printf("creat child failed\n");
}
else if(pid > 0){
sleep(3);
printf("this is father\n");
close(fd[0]);
write(fd[1],"hello from father",strlen("hello form father"));
wait();
}else{
printf("this is child\n");
close(fd[1]);
read(fd[0],buf,128);
printf("read from father: %s\n",buf);
exit(0);
}
return 0;
}
2.有名管道
(1)特点
1.可以在无关的进程之间交换数据
2.有路径名,以一种特别设备文件形式存在于文件系统中,可以用一般的文件I/O函数操作
(2)API
int mkfifo(const char *pathname, mode_t mode);
返回值:成功返回0,失败返回-1
write.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include<errno.h>
#include <fcntl.h>
#include <string.h>
// int mkfifo(const char *pathname, mode_t mode);
int main()
{
int cnt = 0;
char *str = "message from fifo";
if( (mkfifo("./file",IPC_CREAT|0600) == -1) && errno!=EEXIST){
printf("mkfifo failuer\n");
perror("why");
}
int fd = open("./file",O_WRONLY);
printf("write open success\n");
while(1){
write(fd, str, strlen(str));
sleep(1);
if(cnt == 5){
break;
}
}
close(fd);
return 0;
}
read.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include<errno.h>
#include <fcntl.h>
// int mkfifo(const char *pathname, mode_t mode);
int main()
{
char buf[30] = {0};
int nread = 0;
if( (mkfifo("./file",0600) == -1) && errno!=EEXIST){
printf("mkfifo failuer\n");
perror("why");
}
int fd = open("./file",O_RDONLY);
printf("open success\n");
while(1){
nread = read(fd,buf,30);
printf("read %d byte from fifo,context:%s\n",nread,buf);
}
close(fd);
return 0;
}
三.消息队列
1.特点
1.消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先权
2.消息队列对立与发送与接收进程,进程终止时,消息队列及其内容并不会被删除
3.消息队列可以实现消息的随即查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
2.API
1.创建或打开消息队列
int msgget(key_t key, int msgflg);
返回值:成功返回队列ID,失败返回-1
2.添加消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功返回0,失败返回-1
3.读取消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
返回值:成功返回消息数据的长度,失败返回-1
4.控制消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
返回值:成功返回0,失败返回-1
msgget创建一个新队列:
1.如果没有与键值key对应的消息队列,并且flag中包含了IPC_CREAT标志位
2.key参数为IPC_PRIVATE,创建一个私有消息队列
msgrcv在读取时的type参数
type | 含义 |
==0 | 返回消息队列中的第一个消息 |
>0 | 返回队列中消息类型为type的第一个消息 |
<0 | 返回队列中消息类型值小于或等于type绝对值的消息,如果有多个,则取类型值最小的消息 |
msgSend.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// int msgflg);
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main()
{
//1.huoqu
struct msgbuf sendBuf = {888,"this is message from quen"};
struct msgbuf readBuf;
memset(&readBuf,0,sizeof(struct msgbuf));
key_t key;
key = ftok(".",'m');
printf("key=%x\n",key);
int msgId = msgget(key, IPC_CREAT|0777);
if(msgId == -1 ){
printf("get que failuer\n");
}
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
printf("send over\n");
msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),988,0);
printf("reaturn from get:%s\n",readBuf.mtext);
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
msgGet.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// int msgflg);
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main()
{
//1.huoqu
struct msgbuf readBuf;
key_t key;
key = ftok(".",'m');
printf("key=%x\n",key);
int msgId = msgget(key, IPC_CREAT|0777);
if(msgId == -1 ){
printf("get que failuer\n");
}
memset(&readBuf,0,sizeof(struct msgbuf));
msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),888,0);
printf("read from que:%s\n",readBuf.mtext);
struct msgbuf sendBuf = {988,"thank you for reach"};
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
四.共享内存
1.注意事项
共享内存大小以M对齐
2.API
1.创建或获取一个共享内存
int shmget(key_t key, size_t size, int shmflg);
返回值:成功返回共享内存ID,失败返回-1
2.连接共享内存到当前进程的地址空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:成功返回指向共享内存的指针,失败返回-1
shmflg = 0即为可读可写
shmaddr = 0即让内存分配共享空间
3.断开与共享内存的连接
int shmdt(const void *shmaddr);
返回值:成功返回0,失败返回-1
4.控制共享内存的相关信息
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
返回值:成功返回0,失败返回-1
ipcs -m:查看系统中有哪些共享内存
ipcrm -m 共享内存ID :删除共享内存
shmw.c
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
int shmid;
char *shmaddr;
key_t key;
key = ftok(".",1);
shmid = shmget(key,1024*4,IPC_CREAT|0666);
if(shmid == -1){
printf("shmget noOk\n");
exit(-1);
}
shmaddr = shmat(shmid,0,0);
printf("shmat ok\n");
strcpy(shmaddr,"chenlichen");
sleep(5);
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, 0);
printf("quit\n");
return 0;
}
shmr.c
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
int shmid;
char *shmaddr;
key_t key;
key = ftok(".",1);
shmid = shmget(key,1024*4,0);
if(shmid == -1){
printf("shmget noOk\n");
exit(-1);
}
shmaddr = shmat(shmid,0,0);
printf("shmat ok\n");
printf("data: %s\n:",shmaddr);
shmdt(shmaddr);
printf("quit\n");
return 0;
}
五.信号
1.概述
kill -l:查看系统中所有信号
信号处理:忽略、捕捉或默认动作
SIGKILL、SIGSTOP不可忽略
2.API
1.信号处理函数的注册
sighandler_t signal(int signum, sighandler_t handler);
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
忽略信号:SIG_IGN
kill -信号id 进程号:给指定进程发送指定信号
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *); //最后一个参数非空为有数据,为空就是没数据
sigset_t sa_mask; //默认阻塞,处理一个信号
时不处理其他信号
int sa_flags; //SA_SIGINFO:收数据
};
2.信号发送函数
int kill(pid_t pid, int sig);
int sigqueue(pid_t pid, int sig, const union sigval value);
union sigval {
int sival_int;
void *sival_ptr;
};
signalDemo1.c
#include <signal.h>
#include <stdio.h>
// typedef void (*sighandler_t)(int);
// sighandler_t signal(int signum, sighandler_t handler);
void handler(int signum)
{
printf("get signum=%d\n",signum);
switch(signum){
case 2:
printf("SIGINT\n");
break;
case 9:
printf("SIGKILL\n");
break;
case 10:
printf("SIGUSR1\n");
break;
}
printf("never quit\n");
}
int main()
{
signal(SIGINT,SIG_IGN);
signal(SIGKILL,SIG_IGN);
signal(SIGUSR1,handler);
while(1);
return 0;
}
signalDemo1CON.c
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
int main(int argc ,char **argv)
{
int signum;
int pid;
char cmd[128]={0};
signum = atoi(argv[1]);
pid = atoi(argv[2]);
printf("num=%d,pid=%d\n",signum,pid);
// kill(pid, signum);
sprintf(cmd,"kill -%d %d",signum,pid);
system(cmd);
printf("send signal ok");
return 0;
}
NiceSignal.c
#include <signal.h>
#include <stdio.h>
// int sigaction(int signum, const struct sigaction *act,
// struct sigaction *oldact);
void handler(int signum , siginfo_t *info, void *context)
{
printf("get signum %d\n",signum);
if(context != NULL){
printf("from:%d\n",info->si_pid);
// printf("get data=%d\n",info->si_int);
// printf("get data=%d\n",info->si_value.sival_int);
// printf("get data=%s\n",context);
printf("get data=%d\n",*(int *)(info->si_value.sival_ptr));
}
}
int main()
{
struct sigaction act;
printf("pid = %d\n",getpid());
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO; //be able to get message
sigaction(SIGUSR1,&act,NULL);
while(1);
return 0;
}
sendSignal.c
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// int sigqueue(pid_t pid, int sig, const union sigval value)
int main(int argc, char **argv)
{
int signum;
int pid;
union sigval value;
signum = atoi(argv[1]);
pid = atoi(argv[2]);
value.sival_int = 100;
sigqueue(pid,signum,value);
printf("%d,done\n",getpid());
return 0;
}
六.信号量
信号量是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据
1.特点
1.信号量用于进程间同步,若要在进程间传递数据需结合共享内存
2.信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作
3.每次对信号量的PV操作不仅限于对信号量值加1或减1,而且可以加减任意正整数
4.支持信号量组
2.API
1.创建或获取一个信号量组
int semget(key_t key, int nsems, int semflg);
返回值:返回成功返回信号量集ID,失败返回-1
2.对信号量组进行操作
int semop(int semid, struct sembuf *sops, size_t nsops);
返回值:成功返回0,失败返回-1
3.控制信号量的相关信息
int semctl(int semid, int semnum, int cmd, ...);
返回值:成功返回0,失败返回-1
P操作:取信号量
V操作:存信号量
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
// int semget(key_t key, int nsems, int semflg);
// int semctl(int semid, int semnum, int cmd, ...);
// int semop(int semid, struct sembuf *sops, size_t nsops);
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 pHandler(int semid)
{
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = SEM_UNDO;
semop(semid,&sop,1);
printf("get key\n");
}
void vHandler(int semid)
{
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = 1;
sop.sem_flg = SEM_UNDO;
semop(semid,&sop,1);
printf("put back key\n");
}
int main()
{
key_t key;
int semid;
union semun initsem;
int pid;
key = ftok(".",2);
semid = semget(key,1,IPC_CREAT|0666);
initsem.val = 0;
semctl(semid,0,SETVAL,initsem);
pid = fork();
if(pid > 0){
pHandler(semid);
printf("this is father\n");
vHandler(semid);
semctl(semid,0,IPC_RMID);
}else if(pid == 0){
printf("this is child\n");
vHandler(semid);
}else{
printf("fork falied\n");
}
return 0;
}
3.信号量与共享内存结合
send.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <unistd.h>
// int semget(key_t key, int nsems, int semflg);
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 pHandler(int semid)
{
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = SEM_UNDO;
semop(semid,&sop,1);
printf("get key\n");
}
void vHandler(int semid)
{
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = 1;
sop.sem_flg = SEM_UNDO;
semop(semid,&sop,1);
printf("put back key\n");
}
int main()
{
key_t key;
int semid;
union semun initsem;
int shmid;
char *shm;
key = ftok(".",3);
semid = semget(key,1,IPC_CREAT|0666);
printf("semid = %d\n",semid);
initsem.val = 0;
semctl(semid,0,SETVAL,initsem);
shmid = shmget(key,1024*4,IPC_CREAT|0666);
shm = shmat(shmid,0,0);
sprintf(shm,"ccy handsome");
vHandler(semid);
sleep(5);
pHandler(semid);
printf("context:%s\n",shm);
vHandler(semid);
shmdt(shm);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <unistd.h>
// int semget(key_t key, int nsems, int semflg);
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 pHandler(int semid)
{
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = SEM_UNDO;
semop(semid,&sop,1);
printf("get key\n");
}
void vHandler(int semid)
{
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = 1;
sop.sem_flg = SEM_UNDO;
semop(semid,&sop,1);
printf("put back key\n");
}
int main()
{
key_t key;
int semid;
union semun initsem;
int shmid;
char *shm;
key = ftok(".",3);
semid = semget(key,1,IPC_CREAT|0666);
printf("semid = %d\n",semid);
initsem.val = 0;
semctl(semid,0,SETVAL,initsem);
shmid = shmget(key,1024*4,IPC_CREAT|0666);
shm = shmat(shmid,0,0);
pHandler(semid);
printf("context:%s\n",shm);
vHandler(semid);
pHandler(semid);
sprintf(shm,"thank you for using");
vHandler(semid);
shmdt(shm);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
标签:IPC,semid,int,printf,间通信,key,Linux,include
From: https://blog.csdn.net/2303_77402228/article/details/139349958