进程间通信的方式
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。
IPC的方式通常有管道(包括无名管道和命名管道)
消息队列
信号量
共享存储
Socket、Streams等。
其中 Socket和Streams支持不同主机上的两个进程IPC。
1管道
无名管道形式:
#include <unistd.h>
int pipe(int pipefd[2]);
例子
#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
int fd[2];
int pid;
char buf[128];
int status;
if(pipe(fd)==-1)
{
printf("creat pipe error\n");
}
pid =fork();
if(pid<0)
{
printf("creat chuld failed\n");
}
else if(pid>0)
{
sleep(3);
printf("this is father\n");
close(fd[0]);
write(fd[1],"hello",strlen("hell0"));
wait(&status);
}
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、有名管道
有名管道形式:
#include <sys/stat.h>
// 返回值:成功返回0,出错返回-1
int mkfifo(const char *pathname, mode_t mode);
mode 参数与open函数中的 mode 相同。一旦创建了一个 FIFO,就可以用一般的文件I/O函数操作它。
若没有指定O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。
例子:
write:
#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "fcntl.h"
int main()
{
char *str ="message from fifo";
int fd =open("./file1",O_WRONLY);
printf("open succes");
while(1)
{
write(fd,str,strlen(str));
sleep(1);
printf("send a message");
}
close(fd);
return 0;
}
read:
#include "stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "fcntl.h"
#include "errno.h"
#include "unistd.h"
int main()
{
char buf[30]={0};
int n_read=0;
if((mkfifo("./file1",0600)==-1) && errno!=EEXIST)
{
printf("mkfifo failure\n");
perror("why");
}
int fd =open("./file1",O_RDONLY);
printf("open succes\n");
while(1)
{
n_read=read(fd,buf,30);
printf("read %d byte from fifo,context:%s\n",n_read,buf);
}
close(fd);
return 0;
}
3、消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
ftok函数将文件名转化为键值
形式:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
#include <sys/msg.h>
// 创建或打开消息队列:成功返回队列ID,失败返回-1
int msgget(key_t key, int flag);
// 添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag);
// 读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
例子
send:
#include"stdio.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "string.h"
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
struct msgbuf sendBuf={888,"this is massage from que"};
struct msgbuf readBuf;
key_t key;
key=ftok(".",'z');
printf("key:%x\n",key);
int msgid=msgget(key,IPC_CREAT|0777);
if(msgid==-1)
{
printf("get que failure\n");
}
msgsnd(msgid,&sendBuf,sizeof(sendBuf.mtext),0);
printf("send over");
msgrcv(msgid,&readBuf,sizeof(readBuf.mtext),988,0);
printf("reach from get :%s\n",readBuf.mtext);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
get:
#include"stdio.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "string.h"
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
struct msgbuf readBuf;
key_t key;
key=ftok(".",'z');
printf("key:%x\n",key);
int msgid=msgget(key,IPC_CREAT|0777);
if(msgid==-1)
{
printf("get que failure\n");
}
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;
}
4、共享内存
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
函数形式:
#include <sys/shm.h>
// 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
int shmget(key_t key, size_t size, int flag);
// 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
void *shmat(int shm_id, const void *addr, int flag);
// 断开与共享内存的连接:成功返回0,失败返回-1
int shmdt(void *addr);
// 控制共享内存的相关信息:成功返回0,失败返回-1
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
例子
write:
#include <sys/ipc.h>
#include <sys/shm.h>
#include "stdio.h"
#include"string.h"
#include"stdlib.h"
#include "unistd.h"
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 failure\n");
exit(-1);
}
shmaddr=shmat(shmid,0,0);
printf("shmat ok\n");
strcpy(shmaddr,"shaoshuai\n");
sleep(5);
shmdt(shmaddr);
shmctl(shmid,IPC_RMID,0);
printf("Quit\n");
return 0;
}
read:
#include <sys/ipc.h>
#include <sys/shm.h>
#include "stdio.h"
#include"string.h"
#include"stdlib.h"
#include "unistd.h"
int main()
{
int shmid;
char *shmaddr;
key_t key;
key=ftok(".",1);
shmid=shmget(key,1024*4,0);
if(shmid==-1)
{
printf("shmget failure\n");
exit(-1);
}
shmaddr=shmat(shmid,0,0);
printf("shmat ok\n");
printf("data:%s",shmaddr);
shmdt(shmaddr);
printf("Quit\n");
return 0;
}
5、信号
类似中断
入门:
kill:发消息
signal:放消息
例子:
#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;
}
#include <signal.h>
#include"stdio.h"
#include <sys/types.h>
#include <signal.h>
#include"stdlib.h"
int main(int argc,char **argv)
{
int signum;
int pid;
signum=atoi(argv[1]);
pid = atoi(argv[2]);
printf("num=%d,pid=%d\n",signum,pid);
kill(pid,signum);
printf("process killed");
return 0;
}
高级版:
1 #include <sys/sem.h>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);
例子
#include <signal.h>
#include"stdio.h"
#include <sys/types.h>
#include <unistd.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("get data%d\n",info->si_int);
printf("get data:%d\n",info->si_value.sival_int);
printf("from%d",info->si_pid);
}
}
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;
}
~
#include"stdio.h"
#include"signal.h"
#include"stdlib.h"
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int signum;
int pid;
signum=atoi(argv[1]);
pid=atoi(argv[2]);
union sigval value;
value.sival_int=100;
//int sigqueue(pid_t pid, int sig, const union sigval value);
sigqueue(pid,signum,value);
printf("%d,done\n",getpid());
return 0;
}
信号量
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
函数形式:
#include <sys/sem.h>
// 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
int semget(key_t key, int num_sems, int sem_flags);
// 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
int semop(int semid, struct sembuf semoparray[], size_t numops);
// 控制信号量的相关信息
int semctl(int semid, int sem_num, int cmd, ...);
例子:
#include <stdio.h>
#include <stdlib.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);
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 sops;
sops.sem_num = 0; /* Operate on semaphore 0 */
sops.sem_op = -1; /* Wait for value to equal 0 */
sops.sem_flg = SEM_UNDO;
semop(id,&sops,1);
printf("get key\n");
}
void pPutBackKey(int id)
{
struct sembuf sops;
sops.sem_num = 0; /* Operate on semaphore 0 */
sops.sem_op = 1; /* Wait for value to equal 0 */
sops.sem_flg = SEM_UNDO;
semop(id,&sops,1);
printf("put back the key\n");
}
int main(int argc,int const *argv[])
{
key_t key;
int semid;
key = ftok(".",2);
semid=semget(key,1,IPC_CREAT|0666);
union semun initsem;
initsem.val=0;
semctl(semid,0,SETVAL,initsem);
int pid=fork();
if(pid>0)
{
pGetKey(semid);
printf("this is father\n");
pPutBackKey(semid);
}
else if(pid==0)
{
printf("this is child\n");
pPutBackKey(semid);
}
else
{
printf("creat failure");
}
return 0;
}